zoukankan      html  css  js  c++  java
  • 23种设计模式

      本来是想每一种设计模式写一篇随笔,但后来发现了别人的博客已经很完整、详细地做完这种事了。

      从效率的角度来考虑,本人就不重复造轮子了,本随笔只总结了每种设计模式的使用目的,具体实现方法和例子可以去以下链接看。

      别人的博客:https://blog.csdn.net/liang19890820/article/category/6783147

      介绍这些设计模式的视频:https://www.bilibili.com/video/av22292899

      PS:在23种模式全部写完之前都是未完待续!

    1. 模板方法(template method)

      把主程序写到父类文件中,部分子程序写到子类文件中,达到了算法可以灵活变化,且本体不需要进行改变的效果。

      算法的实现是由程序库开发人员写的,他可以保证算法的正确性。后续想用此算法的人,只需根据需求重写一下变化部分,即可轻松调用,代码的复用性和准确性得到了保证。

      具体可以看这里:设计模式—模板方法(template method)

    2. 策略模式(Strategy)

      策略模式就是对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。

      当项目有大量if else时,可以用策略模式,达到后续修改时,只需添加类文件,而不是修改源代码的效果。

      具体可以看这里:设计模式—策略模式

    3. 观察者模式(Observer)

      引用《设计模式》里的定义:

      定义对象间的一种一对多(变化)的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。

      需要时,调用某个通知用途的函数,然后该函数通知所有观察者。

      与UE4的多播委托有点类似。

    4. 装饰模式(Decorator)

      引用《设计模式》里的定义:

      动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类(继承)更为灵活(消除重复代码,减少子类个数)。

      举个简单例子:A有2个子类:B,C; B有2个子类:B1,B2; C有3个子类:C1,C2,C3。

      使用了装饰模式后,B1可以与C1,C2,C3任意组合;B2可以与C1,C2,C3任意组合。

      如果不使用此模式,要达成上述效果,则需要在B的子类中添加大量子类,且有大量重复代码。

      注意:装饰模式有一独特的特点:C的子类既继承A,又组合A。

      这个模式可以明显体验出单一职责原则

      

    5. 桥模式(Bridge)

      引用《设计模式》里的定义:

      将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化。

      如果一个系统存在多个(≥ 2)独立变化的维度,且这多个维度都需要独立进行扩展,则可以使用桥模式。

      这个说明可能会有点玄,可以去别人的博客那里看看,他举了个电器与开关的例子,生动地介绍了桥模式。

    6. 工厂方法(Factory Method)

      引用《设计模式》里的定义:

      定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟(目的:解耦;手段:虚函数)到子类。

      由于简单工厂模式中需要用到switch或者if else来判断实例化哪一个类,但这违背了开放封闭原则。因为每当我们新增一个类,都要去修改该工厂模式(新增类和在switch中添加代码)。

      而本模式中,每个子工厂对应一个产品,调用时,只需自行判断调用哪个子工厂。新增一个类时,只需新增类和其对应的工厂,不需更改代码。(扩展,而不是修改)

    7. 抽象工厂(Abstract Factory)

      引用《设计模式》里的定义:

      提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。

      这个是工厂方法的延伸,或者说工厂方法是抽象工厂的一个特例。

      简单来讲就是,工厂方法只生产一个对象,而抽象工厂则会生产一系列产品,用法大致相同。

      但是,如果在这一系列产品中,要新增一个产品,则需要在每个工厂中新增一个产品,这违背了开放封闭原则!

      所以,如果这一系列产品不是稳定的话,不要使用这种模式!  

    8. 原型模式(Prototype)

      引用《设计模式》里的定义:

      使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。

      通过克隆自己来创建对象。

      由于这个是深拷贝,实现时可能需要复杂的代码。

    9. 构建器(Builder)

      引用《设计模式》里的定义:

      将一个复杂对象的构建与其表示相分离,使得同样的构建过程(稳定)可以创建不同的表示(变化)。

      这个模式,别人的博客中的例子(将配电脑)很生动地描述了,建议去看看。

      说白了就是把构建部分独立出来,方便扩展和使用。

    10. 单件模式(Singleton)

      引用《设计模式》里的定义:

      保证一个类仅有一个实例,并提供一个该实例的全局访问点。

      很简单,就是创建前检查这个类是否存在,如果是,则直接返回此类;如果否,则创建一个,并返回它。

      如果是在多线程的环境下,则需要注意线程安全(double-checked locking)。这个在视频里有详细介绍。

      

    11. 享元模式(Flyweight)

      引用《设计模式》里的定义:

      运用共享技术有效地支持大量细粒度的对象。

      此模式采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对象状态的处理。

    12. 门面模式(Facade)

      引用《设计模式》里的定义:

      为子系统中的一组接口提供一个一致(稳定)的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用(复用)。

      一张图可以很好地解释:  

      

    13. 代理模式(Proxy)

      引用《设计模式》里的定义:

      为其它对象提供一种代理以控制(隔离,使用接口)对这个对象的访问。

      简单来讲就是,如果要调用类A里面的函数,我们可以设计一个类B,它可以调用类A的函数。然后,我们调用类B,起到了调用类A的函数,却不是直接调用类A的效果。

      

    14.适配器(Adapter) 

      当我们想使用旧的一些接口A,但又不想修改它时(修改源代码,特别是很久远之前的代码很可能会出现各种bug。),我们可以使用适配器模式来创造兼用接口A的新接口B,然后调用B。

      适配器分为两种:类适配器和对象适配器。由于类适配器使用的是多继承,不推荐使用,因为有很多问题,视频中有提及。

    15. 中介者(Mediator)

      当我们有很多类关系很密切,这些类之间经常互相调用,构成了一幅很复杂的关系图时,其中的某个类要进行变化都会出现牵一发动全身的危险情况,要考虑的情况会有很多,少考虑一种情况都可能会出现Bug。

      此时,我们可以用中介者模式:把这些类与某个特殊的类进行相互联系,原本的类之间不再有直接联系,原本的类想相互沟通时,将经过一个特殊的类。这个中介者相当于这些类之间的过渡器。

    16. 状态模式(State)

      这个与策略模式差不多。

      State模式将所有与一个特定状态相关的行为都放入一个State的子类对象中,在对象状态切换时,切换相应的对象;但同时维持State的接口,这样实现了具体操作与状态之间的解耦。

    17. 备忘录(Memento)

      当我们想保存对象A的某些状态,一段时间后,想把修改后的对象A恢复回以前保存过的状态时,可以用备忘录模式。

      引用《设计模式》里的定义:

      在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。

    18. 组合模式(Composite)

      如果某个对象内部有复杂的结构,而客户代码又过多地依赖此对象里面的结构,那么该对象内部的结构稍有更改,客户代码也要进行更改,造成维护性、扩展性的弊端。

      此时可以使用组合模式,它使用树状结构,通过递归的手段,把整个结构梳理,用户代码可以轻松调用,且今后不需更改。

      引用《设计模式》里的定义:

      将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。

     19. 迭代器(Iterator)

      对于C++而言,面向对象的迭代器已经过时了,因为其需要频繁地使用虚函数,而虚函数是有成本的,导致效率较低。

      当今时代,泛型编程的迭代器更为流行,它是编译时的多态,性能更好。

    20. 职责链(Chain of Resposibility)

      现在时代下,职责链用的频率不高,有点过时。

      引用《设计模式》里的定义:

      使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。

      将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

    21. 命令模式(Command)

      对于C++而言,由于C++有函数对象,而函数对象与命令模式类似,且效率比命令模式高,故命令模式使用频率较低。

      对于其他语言,如java,C#等,命令模式使用较为广泛。

      引用《设计模式》里的定义:

      将一个请求(行为)封装为一个对象,从而使你可用不同的请求对客户进行参数化;

      对请求排队或记录请求日志,以及支持可撤销的操作。

    22. 访问器(Visitor)

      引用《设计模式》里的定义:

      表示一个作用于其对象结构中的各元素的操作。使得可以在不改变(稳定)各元素的类的前提下定义(扩展)作用于这些元素的新操作(变化)

      简单来讲就是,假设一个对象拥有若干个元素(方法),如果每个访问者对此对象访问时,这些元素的操作都不相同,则可以使用访问器模式来处理。

      但是一旦这个对象要添加或减少某个元素(变化),则很多地方也随之进行修改(变化),这违背了开发封闭原则。

      故要使用访问器模式的前提是这个对象的元素是稳定的,以后都不需要更改的。但一般情况下,是很难做到的。

      访问器这一局限性导致其使用率低下。

    23. 解析器(Interpreter)

      引用《设计模式》里的定义:

      给定一个语言,定义它的文法的一种表示,并定义一种解析器,这个解释器使用该表示来解释语言中的句子。

      适合使用解析器的情况:业务规则频繁变化,且类似的结构不断重复出现,并且容易抽象为语法规则的问题。

      这个与字符串算法—正则表达式类似,也是把规律提取出来,变成表达式。不同点在于,面向对象的解析器使用了虚函数,表达式算法可以经常变化。

      但是,对于复杂的规则,解析器就不适用了,会产生类结构复杂、难以调试等问题,这时候需要求助于语法分析生成器这样的标准工具。

  • 相关阅读:
    SDOI Day2
    SDOI Day1
    Codeforces 506E Mr. Kitayuta's Gift (矩阵乘法,动态规划)
    CEOI 2014 wall (最短路)
    BZOJ 3926: [Zjoi20150]诸神眷顾的幻想乡(后缀自动机)
    BZOJ 3925: [Zjoi2015]地震后的幻想乡(概率)
    BZOJ 3924: [Zjoi2015]幻想乡战略游戏(动态点分治)
    Nginx与Lua的开发
    Nginx访问控制
    Nginx模块
  • 原文地址:https://www.cnblogs.com/mcomco/p/10779190.html
Copyright © 2011-2022 走看看