Java设计模式
- 设计模式
- 创建型模式
- 单例模式
- 工厂模式
- 建造者模式
- 原型模式
- 行为型模式
- 策略模式
- 责任链模式
- 结构型模式
- 适配器模式
- 装饰者模式
- 外观模式
- 代理模式
- 享元模式
- 桥接模式
设计模式
参考:菜鸟教程
六大原则
- 开闭原则(Open Close Principle): 一个软件实体应当对扩展开放,对修改关闭。开闭原则也是其他五个原则的基石
- 单一职责原则(Single Responsibility Principle):一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。
- 里氏代换原则(Liskov Substitution Principle):所有引用基类(父类)的地方必须能透明地使用其子类的对象。
- 依赖倒置原则(Dependence Inversion Principle):程序要依赖于抽象接口,不要依赖于具体实现。
- 接口隔离原则(Interface Segregation Principle):使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
- 迪米特法则(Law of Demeter, LoD)(最少知道原则):一个软件实体应当尽可能少地与其他实体发生相互作用。
设计模式solid六大原则
三大分类
创建型模式:
工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式:
适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式:
策略模式、模板方法模式、观者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
创建型模式
单例模式
保证在同一个进程只拥有一个实例
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
实现:
- 持有一个该例的全局静态变量 public static Earth earth;
- 将构造方法私有 private
- 创建外部调用方法返回实例
饿汉式:线程安全,但是在类加载时就初始化,浪费内存,容易产生垃圾对象
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
懒汉式:加上synchronized 才能实现线程安全,但是效率比较低
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
最佳实现:双重校验锁
双重校验是为了防止第一个判定未获取到锁时间,判断为空后失去被CPU调度走了造成单例失效
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
工厂模式
抽象统一的接口,将类的创建移到工厂类当中,只要告诉工厂类需要什么东西,就直接拿到工厂“生产”的产品,而不需要关心具体的创建过程
菜鸟教程
使用步骤:
- 抽象对象统一接口,对不同的类有各自自己的实现
- 创建工厂类,根据传入不同的标识,返回不同的实现对象
- 拿到实现的对象,接口
建造者模式
- 当一个对象由若干个基本对象组成,但是产出的结果是相同的
- 产品内部调用顺序不同会导致不同的结果
- 初始化对象非常复杂,有很多个构造方法或者很多参数由默认值时
使用步骤:
- 抽象化产品类
- 抽象Builder,规范产品组建
- 创建具体类的Builder
- 创建Director类,负责构造具体的产品类
链式多参数调用:参考okhttp源码Request的Builder
推荐阅读
原型模式
当从数据库等取出相似对象需要耗费大量时间时,可以通过预先加载好对象,然后通过clone方法,快速的得到一个所需对象。
使用场景:
- 需要耗费较大的资源去创建一个重复对象
- 与工厂模式进行配合
菜鸟教程
行为型模式
策略模式
使用场景
- 当多个场景的算法、行为十分相似,造成大量的if…else…难以维护;又或者有多个类,他们之前的区别只是行为不同;
- 可以用于解耦代码
角色
- 设计行为接口,例如登录: ILoginStrategy
- 具体的实现类,例如WXLogin、QQLogin等
- 策略环境类:LoginContextStrategy,持有具体行为类(例如WXLogin),根据实际场景调用行为类具体实现方法
实例参考:
- 程序员小灰 公众号文章
- 菜鸟教程
责任链模式
责任链模式就是将接收者对象连成一条链,并在该链上传递请求,直到有一个接收者对象处理它。通过让更多对象有机会处理请求,避免了请求发送者和接收者之间的耦合。
- 设计统一接口(处理、设定下一级处理对象)
- 工厂类,组装责任链
- 发起调用,根据具体逻辑依次调用直到符合条件
实例:
- 参考
- okhttp源码的拦截器链
结构型模式
适配器模式
使用场景
需要将一个接口转换成客户需要的另一个接口,使原本由于接口不兼容而不能一起工作的类可以一起工作,提高类的复用
- Android经典实现 :Android 设计模式之适配器模式
- retrofit 里面的Call转换和result转换器
装饰者模式
使用场景:
需要拓展某个类的功能,同时不影响原有类;
在不想增加很多子类的情况下扩展类。
特点
装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
例子:
菜鸟教程
外观模式
使用场景:
为一组相似的行为,进行一个统一的封装,调用者不需要知道内部如何实现,简化逻辑、减少错误;
- 降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口。
- 为复杂的模块或子系统提供外界访问的模块,且子系统相对独立
- 在层次化结构中,可以使用外观模式定义系统中每一层的入口。
常用于SDK或者三方开源库为调用者提供一个统一的入口
代理模式
作用描述:
在不改变原对象的前提下,提供一种方式操作原对象(访问一个类时做一些控制)
分类:分为静态代理和动态代理(代码编译时不知道具体是哪个类)
原理:JDK动态代理是基于Java的反射机制实现的原理参考这篇,并且只能代理接口,JDK为帮我们生成一个继承于proxy类和代理接口的代理类
实例
public interface IEat {
String eatSomething(String food);
}
// 实现类
public class EatImpl implements IEat {
@Override
public String eatSomething(String food) {
int time = (int) (Math.random() * 1000);
return String.format("Eat %s with %d second",food,time);
}
}
// 静态代理
public class EatProxy implements IEat {
IEat iEat;
public EatProxy(IEat iEat) {
this.iEat = iEat;
}
@Override
public String eatSomething(String food) {
System.out.println("do something before eating");
return iEat.eatSomething(food);
}
}
// 动态代理实现
public class EatHandler implements InvocationHandler {
private Object object;
public EatHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("do something before eating in EatHandler");
Object result = method.invoke(object,args);
return result;
}
}
// 测试类
public class ProxyTest {
public static void main(String[] args) {
IEat iEat = new EatImpl();
EatProxy eatProxy = new EatProxy(iEat);
IEat eatHandler = (IEat) Proxy.newProxyInstance(iEat.getClass().getClassLoader(),iEat.getClass().getInterfaces(),new EatHandler(iEat));
System.out.println(eatProxy.eatSomething("meet"));
System.out.println( eatHandler.eatSomething("Vegetables"));
}
}
// 输出结果
do something before eating
Eat meet with 842 second
do something before eating in EatHandler
Eat Vegetables with 333 second
享元模式
作用描述:
如果在一个系统中存在多个相同的对象,那么只需要共享一份对象的拷贝,而不必为每一次使用都创建新的对象。目的是提高系统性能,避免重复创建对象
和单例模式区别
单例模式保存的是一个单个类的状态,享元模式是共享对象,避免大量创建重复对象
三个角色
- 抽象外部键值接口,用于标识同一类别
- 享元工厂,用来获取对象
- 具体享元对象
Book接口和实现类
// IBook接口 抽象出书名
public interface IBook { void borrow(); }
// 具体实现类 省略 get、set方法
private String name;
private String mark;
public Book(String name) {
this.name = name;
}
@Override
public void borrow() {
System.out.println("borrow book ,name : " + name);
}
@Override
public String toString() {
return "阅读的书本名:" + name +
" 笔记内容:" + mark;
}
享元工厂类:
public class BookFactory {
private static volatile BookFactory sInstance;
private HashMap<String,Book> bookPool = new HashMap<>();
public static BookFactory getsInstance() {
if (sInstance == null){
synchronized (BookFactory.class){
if (sInstance == null){
sInstance = new BookFactory();
}
}
}
return sInstance;
}
public Book getBook(String name){
if (bookPool.containsKey(name)){
System.out.println("存在" + name + ",直接借出");
return bookPool.get(name);
}
System.out.println("书本:" + name + " 不存在,创建并返回");
Book book = new Book(name);
bookPool.put(name,book);
return book;
}
public int getBookListSize(){
return bookPool.size();
}
}
测试类以及输出
public class BookMainTest {
public static void main(String[] args) {
BookFactory bookFactory = BookFactory.getsInstance();
Book book = bookFactory.getBook("Java从入门到放弃");
bookFactory.getBook("Android从入门到放弃");
bookFactory.getBook("第一行代码");
bookFactory.getBook("第二行代码");
bookFactory.getBook("第三行代码");
// 做笔记
book.setMark("小明的java读书笔记");
System.out.println(book.toString());
// 被别人借走了,又做了笔记
bookFactory.getBook("第二行代码");
Book book1 = bookFactory.getBook("Java从入门到放弃");
book1.setMark("小红的java读书笔记");
System.out.println(book.toString());
System.out.println("图书馆存在" + bookFactory.getBookListSize() + "本书");
}
}
// 输出:
书本:Java从入门到放弃 不存在,创建并返回
书本:Android从入门到放弃 不存在,创建并返回
书本:第一行代码 不存在,创建并返回
书本:第二行代码 不存在,创建并返回
书本:第三行代码 不存在,创建并返回
阅读的书本名:Java从入门到放弃 笔记内容:小明的java读书笔记
存在第二行代码,直接借出
存在Java从入门到放弃,直接借出
阅读的书本名:Java从入门到放弃 笔记内容:小红的java读书笔记
图书馆存在5本书
桥接模式
参考这篇文章
更多推荐
Java设计模式
发布评论