美文网首页技术设计模式
常见设计模式总结

常见设计模式总结

作者: s1991721 | 来源:发表于2018-10-21 18:33 被阅读9次

    分类


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

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

    定义来自权威的软考

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

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

    正文


    Builder构建者

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

    • 例子


      OkHttpClient

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

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

    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中

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

    初始化阶段,将实例化的不同工厂放在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类

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

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

    接口适配器模式

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

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

    如OkHttp中的回调监听EventListener

    所有阶段的回调都空实现,当我关心某一阶段的回调时,就重写对应方法,否则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,其中的链是环形链


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

    相关文章

      网友评论

        本文标题:常见设计模式总结

        本文链接:https://www.haomeiwen.com/subject/wzwmzftx.html