常见设计模式总结

分类


设计模式共分为三种类型:创建型、结构型、行为型

  • 创建型:用于创建对象,为设计类实例化新对象提供指南
  • 结构型:用于处理类或对象的组合,对类如何设计以形成更大的结构提供指南
  • 行为型:用于描述类或对象的交互以及职责的分配,对类之间交互以及分配职责的方式提供指南

定义来自权威的软考

常见的设计模式有如下几种

创建型:构建者、单例、工厂
结构型:适配器、代理、外观
行为型:策略、观察者、责任链

正文


Builder构建者

  • 场景
    用于生成对象的类其内部结构过于复杂,为屏蔽类的复杂性,需要将类的构建和表示进行分离,用最少的参数生成对象

  • 例子


    常见设计模式总结_第1张图片
    OkHttpClient

产生实际对象的必需参数是从builder对象中取出的

即使什么参数也不传Builder也会生成默认参数,以支持对象的生成

常见设计模式总结_第2张图片
Builder

每次添加参数时,记得返回Builder对象,用以链式的传递

这是OkHttpClient对象传递参数的精妙之处,源码内多处使用

Singleton单例

  • 场景
    保证实例是唯一的存在,以保证操作的唯一性

单例模式的实现有两种:饱汉、饿汉模式
联想记忆:饱汉不饿,需要的时候再吃;饿汉很饥,提前抢着吃
饱汉其实是懒加载,不必提前占内存

  • 例子
//饱汉模式
public class SingletonClass{
    private static volatile SingletonClass instance=null;//静态变量保证对象的唯一性,volatile关键字防止指令重排

    public static SingletonClass getInstance(){//使用内部加锁,避免每次调用时无谓的加锁,提升了性能
        if(instance==null){//指令重排的话,其他线程看到instance不空,则不会进入,也不会加锁,直接返回半成品instance,从而导致异常
            synchronized(SingletonClass.class){//锁对象最好是类对象(个人观点)
                if(instance==null)//再判断一遍,避免多个线程在上一行同时被锁住,释放后进入,再次实例化对象
                    instance=new SingletonClass();//指令重排发生地
            }
        }
        return instance;
    }

    private SingletonClass(){//私有构造方法,防止实例化
    }
}
//饿汉模式
public static class Singleton{//静态类直接进入方法区常量池

    private static final Singleton instance = new Singleton();//静态常量进入方法区常量池

    private Singleton(){//私有构造方法,防止实例化
    }

    public static Singleton getInstance(){//静态方法
        return instance;
    }
}

饿汉模式,由于事先分配内存空间不存在饱汉的多线程问题,但其常驻内存会造成开销问题,不同的场景需采用不同的手段以保证消耗与效率的平衡。

Factory工厂

  • 场景
    多态场景下,用以管理生成不同的对象,并且耦合度不能够过高

  • 例子

简单工厂模式

public interface Phone {//Phone是产品抽象
}

public class Honor implements Phone{//Honor是具体的产品
}

public class Mate20 implements Phone{//Mate20是具体的产品
}

public class HuaWei {//具体的厂商

    public static Phone create(String str){//厂商根据要求生产手机
        
        if(str.equalsIgnoreCase("honor")){
            return new Honor();
        }
        else if(str.equalsIgnoreCase("mate20")){
            return new Mate20();
        }
        return null;
    }

}

工厂方法模式

public interface Phone {//Phone是产品抽象
}

public interface Factory {//Factory是厂商抽象
    public Phone create();
}

public class HWPhone implements Phone{//华为手机
}

public class MPhone implements Phone{//小米手机
}

public class HuaWei implements Factory {//华为产华为手机
    public Phone create(){
        return new HWPhone();
    }
}

public class XiaoMi implements Factory {//小米产小米手机
    public Phone create(){
        return new MPhone();
    }
}

简单工厂模式:一个工厂类,工厂生产各种产品

工厂方法模式:一个工厂接口,多个工厂类,不同工厂生产不同产品

工厂方法模式的改进在于,减轻了简单工厂模式中工厂类的复杂度,具体的产出交由具体的工厂类,降低了耦合度。

抽象工厂模式

public interface Phone {//Phone是产品抽象
}

public interface OS {//OS是产品抽象
}

public interface Factory {//Factory是厂商抽象
    public Phone create();

    public OS develop();
}

public class HWPhone implements Phone{//华为手机
}

public class MPhone implements Phone{//小米手机
}

public class MIUI implements OS{//系统
}

public class EMUI implements OS{//系统
}

public class HuaWei implements Factory{//华为产华为手机
    public Phone create(){
        return new HWPhone();
    }

    public OS develop(){
        return new EMUI();
    }
}

public class XiaoMi implements Factory{//小米产小米手机
    public Phone create(){
        return new MPhone();
    }
    public OS develop(){
        return new MIUI();
    }
}

抽象工厂模式较工厂方法模式的区别在于,不生产单一产品,使工厂能够生产不同类型的相关产品,从而提高扩展性

在Retrofit中

常见设计模式总结_第3张图片

使用的是工厂方法模式,将工厂抽象

常见设计模式总结_第4张图片

初始化阶段,将实例化的不同工厂放在List中,根据参数使用情景的不同,再在List中取出合适的工厂进行处理。

Adapter适配器

  • 场景
    已有类的功能不满足需求,需将功能进行转换,以达到匹配

  • 例子

类适配器模式

原有类并不具备某功能,通过创建Adapter类,继承原有功能、实现目标功能接口,从满足功能要求

public class Source {//现有类
    public void method1() {  
        System.out.println("this is original method!");  
    }  
}  

public interface Targetable {//目标功能
  
    public void method1();  
  
    public void method2();//缺失功能
}  

public class Adapter extends Source implements Targetable {  
  
    @Override  
    public void method2() {//补足缺失
        System.out.println("this is the targetable method!");  
    }  
} 

对象适配器模式

不同于类适配器模式,通过继承、实现这种高耦合手段,以满足功能要求。对象适配器模式采用的是聚合的手段,创建新类Wrapper通过持有原类对象具备原有功能外;并且类Wrapper实现功能接口补足缺失功能

如OkHttpClient中的Cache类

常见设计模式总结_第5张图片

在OkHttpClient中缓存拦截器一层使用的是InternalCache,见注释,官方已经不建议使用此类改用Cache

常见设计模式总结_第6张图片

Cache类本身并没有实现InternalCache接口,而是持有一个InternalCache对象,且对象内的方法都是调用Cache内的

接口适配器模式

不同于类适配器模式、对象适配器模式的补足功能,接口适配器模式恰恰相反:不暴露功能。

当接口方法过多,而我们关心的却寥寥可数时,通过实现接口的方式就会空实现很多不必要的方法。通过,创建新类(或抽象类)空实现所有方法,实际使用时继承自新类重写关心的方法,就避免了每次实现方法过多的问题,这种设计的原则是接口隔离,对接口知道的越少越好

如OkHttp中的回调监听EventListener

常见设计模式总结_第7张图片

所有阶段的回调都空实现,当我关心某一阶段的回调时,就重写对应方法,否则20个回调方法每添加一次监听就都要实现一遍,代码的易读性也不好

Proxy代理

代理分静态代理和动态代理,这里列举的是静态代理

  • 场景
    原有类的功能需要进行扩充

  • 例子

public interface Sourceable {  
    public void method();  
} 

public class Source implements Sourceable {//原类
  
    @Override  
    public void method() {  
        System.out.println("the original method!");  
    }  
}  

public class Proxy implements Sourceable {//代理类
  
    private Source source;  
    public Proxy(){  
        super();  
        this.source = new Source();  
    }  
    @Override  
    public void method() {  
        before();  
        source.method();  
        atfer();  
    }  
    private void atfer() {  
        System.out.println("after proxy!");  
    }  
    private void before() {  
        System.out.println("before proxy!");  
    }  
}  

原类与代理类都实现了相同的接口,方法的实际执行是由代理对象触发的,只不过代理对象在方法触发前后增加了其他功能。

有点和对象适配器模式类似都实现相关接口、持有原类对象,但

  • 对象适配器模式是为了弥补功能上的不足
  • 代理模式是给功能进行加强

一个是弥补功能,一个是加强功能这是两种模式的区别

从上来看对象适配器模式中的Cache例子放错位置了,它应该属于静态代理模式,Cache是被代理类,InternalCache是代理类

Facade外观

  • 场景
    多个类间有依赖关系时,由多个类组合创建新类

  • 例子

OkHttpClient和Retrofit类就是明显的外观模式,其内部由多个功能不同的类对象组成,外部的单一操作实际影响内部多个对象间的联动。

Strategy策略

  • 场景
    相同的方法,根据不同的情景有不同的实现

  • 例子
    以前做过比特币的自动交易软件,实际操作就两种:买、卖,但是针对不同的行情、手上的持仓和现金情况,买和卖就变得有学问了:
    行情好的时候采用激进策略,大胆买卖;
    行情差的时候就要高抛低吸,慢慢来;

Observer观察者

  • 场景
    某一对象状态发生变化时,其他对象需要及时的告知

  • 例子
    android中的回调就是观察者模式,简单点的:给一个button设置onClickListener,此时观察者就是onClickListener被观察者是button,setOnClickListener是给两者创建关联,当被观察者button被单击,观察者onClickListener就会作出回应。

Chain of Responsibility责任链

  • 场景
    问题一次得不到解决,需要层层处理并传递,每次将任务细化

  • 例子
    最有名的当数OkHttp,其中的链是环形链

常见设计模式总结_第8张图片

有些自己用的比较熟的或没太多重点要记录的就没有贴例子,一般这种模式比较常见且简单

你可能感兴趣的:(常见设计模式总结)