设计模式大杂烩(概念)

 

一. 23种设计模式汇总整理 

一.设计模式
模式是一种问题的解决思路,它已经适用于一个实践环境。并且可以适用于其他环境。
作用:设计的重用;
为设计提供共同的词汇,每个模式名就是一个设计词汇,其概念使程序员方便交流;
在开发文档中采用模式可以让其他人更容易理解你的看法。
分类:根据目的的准则
1.创建型:与对象的创建有关
2.结构性:处理类或对象之间的组合
3.行为性:描述类或对象如何交互及其如何分配职责。

二.设计模式的六大原则:
总原则-开闭原则
对扩展开放,对修改封闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。
想要达到这样的效果,我们需要使用接口和抽象类等,后面的具体设计中我们会提到这点。
1、单一职责原则
不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,否则就应该把类拆分。
2、里氏替换原则(Liskov Substitution Principle)
任何基类可以出现的地方,子类一定可以出现。里氏替换原则是继承复用的基石,只有当衍生类可以替换基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
里氏代换原则是对“开-闭”原则的补充。实现“开闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。里氏替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。
3、依赖倒转原则(Dependence Inversion Principle)
面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。
4、接口隔离原则(Interface Segregation Principle)
每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。
5、迪米特法则(最少知道原则)(Demeter Principle)
一个类对自己依赖的类知道的越少越好。无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。
最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。
6、合成复用原则(Composite Reuse Principle)
尽量首先使用合成/聚合的方式,而不是使用继承。

之前已经陆续整理了9种设计模式,链接如下,接下来一段时间陆续把剩余的过一遍,整理出来,理解设计模式还是很重要的。

创建型模式:工厂方法模式抽象工厂模式单例模式建造者模式原型模式
结构型模式:适配器模式装饰者模式代理模式外观模式桥接模式组合模式享元模式
行为型模式:策略模式模板方法模式观察者模式迭代子模式责任链模式命令模式备忘录模式状态模式访问者模式中介者模式、解释器模式
还有两类:并发型模式和线程池模式。
-------2017年8月31日更新----------------
设计模式需要几个阶段的学习,没有大量项目经验的时候学习,可能只是了解,当有了一些项目场景的时候,才会深刻体会到其中的奥妙。
上面文章有些在写的时候,“借鉴”甚至“抄袭”了很多其他博主的文章,主要也是当时自己理解的不够深刻,需要借助现有的场景去理解,
三.设计模式分为三大类:
创建型模式,共5种: 单例模式、工厂方法模式、抽象工厂模式、 建造者模式、原型模式。
结构型模式,共7种:  代理模式、桥接模式、 适配器模式、装饰器模式、  外观模式、组合模式、享元模式。
行为型模式,共11种: 观察者模式、模板方法模式、策略模式、责任链模式、 迭代子模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
其实还有两类:并发型模式和线程池模式。
-------创建型模式5种
  1、单例模式:确保某一个类只有一个实例,而且自行实例化 并 提供一个访问它的全局控制点。 单例模式只应在有真正的“单一实例”的需求时才可使用。

  2、工厂方法模式:   

    定义一个创建对象的接口,让子类决定实例化哪个类。当遇到需要根据某个前提条件创建不同的类实现时,会使用工厂模式。

     核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。 

  3、工厂模式:

        提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类;

        客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。

        缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。 

  4、建造模式:将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。 建造模式可以强制实行一种分步骤进行的建造过程。 
  5、原始模型模式:通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。原始模型模式允许动态的增加或减少产品类,产品类不需要非得有任何事先确定的等级结构,原始模型模式适用于任何的等级结构。缺点是每一个类都必须配备一个克隆方法。 
------- 结构型模式7种
  6、代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入。
    代理:Proxy.为其他对象提供一种代理以控制对这个对象的访问。

比如:在用户登录时候,真正的登录类和代理登录类都实现Login接口,不同的是Proxy类中方法增加了用户是否合法的判断,只有合法时才去调用真正登录类的login方法,用户访问的其实是Proxy中的login()。

  7、桥接模式:将抽象化与实现化脱耦,使得二者可以独立的变化,也就是说将他们之间的强关联变成弱关联,也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立的变化。 
  8、适配器(变压器)模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。 
    9、装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。 
 --动态的给一个对象添加一些额外的职责。
如java.io包,BufferedInputStream封装了FileInputStream,他们都实现了InputStream接口,但BufferedInputStream实现了 readLine();
 10、门面模式:外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。每一个子系统只有一个门面类,而且此门面类只有一个实例,也就是说它是一个单例模式。但整个系统可以有多个门面类。 
 11、享元模式:FLYWEIGHT在拳击比赛中指最轻量级。享元模式以共享的方式高效的支持大量的细粒度对象。享元模式能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部,不会随环境的改变而有所不同。外蕴状态是随环境的改变而改变的。外蕴状态不能影响内蕴状态,它们是相互独立的。将可以共享的状态和不可以共享的状态从常规类中区分开来,将不可以共享的状态从类里剔除出去。客户端不可以直接创建被共享的对象,而应当使用一个工厂对象负责创建被共享的对象。享元模式大幅度的降低内存中对象的数量。 
   12、合成模式:合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式就是一个处理对象的树结构的模式。合成模式把部分与整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由他们复合而成的合成对象同等看待。 
------- 行为型模式共11种
     13、观察者模式:观察者模式定义了一种一队多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。 
观察者:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象,在它的状态发生变化时,会通知所有的观察者。

 如:ServletContextListener,在application启动时,会通知所有这个接口的实现类。

   15、策略模式:策略模式针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。策略模式把行为和环境分开。环境类负责维持和查询行为类,各种算法在具体的策略类中提供。由于算法和环境独立开来,算法的增减,修改都不会影响到环境和客户端。

策略模式:定义了算法家族,分别封装起来,让它们之间可以互相替换。

比如:Collections.sort(List list,Comparator com); 可通过实现多个Comparator接口来达到多种排序的目的。

  16、责任链模式:在责任链模式中,很多对象由每一个对象对其下家的引用而接
  起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的情况下动态的重新组织链和分配责任。处理者有两个选择:承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象所接受。 

    14、模板方法模式:模板方法模式准备一个抽象类,将部分逻辑以具体方法以及具体构造子的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先制定一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。

模板方法模式:
定义一个操作中的算法骨架,而将一些步骤延迟到子类中。
优点:1)提取公共部分代码,易于维护 2)由父类控制,子类实现;3)封装不可变部分,扩展可变部分。

     17、访问者模式:访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。访问者模式使得增加新的操作变的很容易,就是增加一个新的访问者类。访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。当使用访问者模式时,要将尽可能多的对象浏览逻辑放在访问者类中,而不是放到它的子类中。访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。
  17、命令模式:命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。命令模式允许请求的一方和发送的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否执行,何时被执行以及是怎么被执行的。系统支持命令的撤消。 
  18、解释器模式:给定一个语言后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。解释器模式将描述怎样在有了一个简单的文法后,使用模式设计解释这些语句。在解释器模式里面提到的语言是指任何解释器对象能够解释的任何组合。在解释器模式中需要定义一个代表文法的命令类的等级结构,也就是一系列的组合规则。每一个命令对象都有一个解释方法,代表对命令对象的解释。命令对象的等级结构中的对象的任何排列组合都是一个语言。 
  19、迭代子模式:迭代子模式可以顺序访问一个聚集中的元素而不必暴露聚集的内部表象。多个对象聚在一起形成的总体称之为聚集,聚集对象是能够包容一组对象的容器对象。迭代子模式将迭代逻辑封装到一个独立的子对象中,从而与聚集本身隔开。迭代子模式简化了聚集的界面。每一个聚集对象都可以有一个或一个以上的迭代子对象,每一个迭代子的迭代状态可以是彼此独立的。迭代算法可以独立于聚集角色变化。 
  20、调停者模式:调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用。从而使他们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用。保证这些作用可以彼此独立的变化。调停者模式将多对多的相互作用转化为一对多的相互作用。调停者模式将对象的行为和协作抽象化,把对象在小尺度的行为上与其他对象的相互作用分开处理。 
  21、备忘录模式:备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。 
  22、状态模式:状态模式允许一个对象在其内部状态改变的时候改变行为。这个对象看上去象是改变了它的类一样。状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。 

二.设计模式大杂烩

http://www.cnblogs.com/zuoxiaolong/p/pattern26.html

24种设计模式介绍完了,其中包括GOF23种设计模式以及简单工厂模式,这些设计模式之间并不是完全独立的。下面总结下24种设计模式。

模式分类 & 传送门 & 对比维度说明

        以上便是设计模式的分类以及各个模式的传送门,可以看到其中行为型模式的个数为最多,结构型次之,创建型设计模式最少。

        在写这篇文章的时候,LZ考虑的最多的一个问题就是,从哪几个维度去对比设计模式能让大家更加清楚的看出各个设计模式的区别与联系,思来想去,LZ决定从以下几个维度去对比设计模式。 

  • 设计原则:描述每个设计模式都遵循了哪些设计原则,破坏了哪些设计原则。
  • 常用场景:描述各个设计模式大部分情况下,都会在哪些场景下出现。
  • 使用概率:主要指在普遍的工作当中,该设计模式出现的频率,若是类库或是开源框架提供的功能中包含该模式,则也会计算其频率。
  • 复杂度:特指一个设计模式在实现的时候的复杂度,主要的衡量标准是类的数量、类之间的耦合关系。
  • 变化点:设计模式很大的一个意义在于容纳变化,掌握一个设计模式的变化点是非常重要的一件事。
  • 选择关键点:当选择使用一个设计模式的时候,指出最关键的选择点在哪里。
  • 逆鳞:龙有逆鳞,不可触摸,同样的,设计模式也有逆鳞,有些地方是不能碰的。
  • 相关设计模式:与其它设计模式的关系。

结束语

        此外需要说明的是,上面的概率当中有的会出现99.99999%这样的数字,这是因为这个模式已经嵌入到JAVA类库或是我们常用的开源框架当中(标注一下:LZ总结的主要针对WEB开发,android的开发LZ并未接触过,所以不包括在此列),比如迭代器模式,只要你使用过ArrayList或者HashSet,LZ就认为这个模式被使用。这个使用频率从某种意义上讲,可以认为是该模式的重要程度。

        1、之前说过,学习设计模式除了努力之外还要靠缘分,所以如果有设计模式当时怎么看都不明白,可以暂且放下,之后说不定哪天你突然之间就明白了。(此话并非虚言,LZ很多次的顿悟常发生在上厕所、洗澡、回家路上等一些学习之外的时候。)

        2、对于已经在工作的人来说,可以常思考一下,有没有哪个设计模式可以改善现有的系统架构,但不要轻易付诸实践。

        3、学习设计模式之前,一定要先整明白UML类图,什么关联,依赖,聚合,组合等等都得搞明白儿的,否则学习起来也依然会很吃力。

        4、对于初学者,一定要在弄清楚标准的实现代码之后,写一个属于自己的例子,哪怕是比葫芦画瓢,然后仔细体会设计模式使用前后的差异,主要从扩展性和类(类包括客户端,而不仅仅指设计模式中的角色)的职责两个方面。

        5、一定要将设计模式的变化点搞清楚,这点非常重要,甚至重要程度高于设计模式的场景、实现方式以及类和对象之间的耦合关系,很多时候,设计模式的滥用就是因为变化点没搞清楚,以至于该变化的没变化,不该变化的经常变化,增加系统的负担。

        6、设计模式不是一次性学习完就可以扔掉不看的东西,而是要经常回过头来看看,说不定每一次你都有不一样的体会,而且一般情况下,这些体会会越来越深刻,越来越透彻。

        7、如果可能的话,多研究一些开源框架,去找找它们里面的设计模式。

        LZ暂时也就只能想到这些,如果以后有想到再补充吧,各位如果有什么好的建议也可以与LZ分享一下。

        到此为止,整个设计模式系列就真真正正的彻底结束了,当初写的时候也没想到自己可以真的坚持下来,虽说整整26篇文章不算多,但是LZ确实花费了大量的时间和精力,值得欣慰的是LZ本人也得到了巨大的收获,不仅仅是对设计模式的理解日益加深,而且还得了不少猿友的支持,让LZ对分享这一道路更加坚定。

        以后的编程之路还很长,对于LZ来说,编程并不仅仅是工作,而是一份事业,它给了LZ荣誉、金钱、成就感等等很多东西,希望各位至少在年轻的时候不要被一些悲观化的观点所干扰,特别是对编程有着热爱的猿友们,极致才能成就大道,但凡在一个领域有所成就者,大都是钻研了数十年的成果。

创建型设计模式

单例模式

  • 设计原则:无
  • 常用场景:应用中有对象需要是全局的且唯一
  • 使用概率:99.99999%
  • 复杂度:低
  • 变化点:无
  • 选择关键点:一个对象在应用中出现多个实例是否会引起逻辑上或者是程序上的错误
  • 逆鳞:在以为是单例的情况下,却产生了多个实例
  • 相关设计模式
    • 原型模式:单例模式是只有一个实例,原型模式每拷贝一次都会创造一个新的实例。

简单工厂模式

  • 设计原则:遵循单一职责、违背开闭原则
  • 常用场景:需要在一堆产品中选择其中一个产品
  • 使用概率:99.99999%
  • 复杂度:低
  • 变化点:产品的种类
  • 选择关键点:一种产品是否可根据某个参数决定它的种类
  • 逆鳞:工厂类不能正常工作
  • 相关设计模式
    • 工厂方法模式:工厂方法模式是简单工厂模式的进一步抽象化,在这两者之间做选择,主要看将工厂进一步抽象化是否有必要,通常情况下,如果工厂的作用仅仅是用来制造产品,则没必要使用工厂方法模式。

工厂方法模式

  • 设计原则:遵循单一职责、依赖倒置、开闭原则
  • 常用场景:一种场景是希望工厂与产品的种类对客户端保持透明,给客户端提供一致的操作,另外一种是不同的工厂和产品可以提供客户端不同的服务或功能
  • 使用概率:60%
  • 复杂度:中低
  • 变化点:工厂与产品的种类
  • 选择关键点:工厂类和产品类是否是同生同灭的关系
  • 逆鳞:无
  • 相关设计模式
    • 抽象工厂模式:工厂方法模式与抽象工厂模式最大的区别在于,在工厂方法模式中,工厂创造的是一个产品,而在抽象工厂模式中,工厂创造的是一个产品族。

抽象工厂模式

  • 设计原则:遵循单一职责、依赖倒置、开闭原则
  • 常用场景:需要一个接口可以提供一个产品族,且不必知道产品的具体种类
  • 使用概率:30%
  • 复杂度:中
  • 变化点:工厂与产品的种类
  • 选择关键点:产品族是否需要一起提供,且是否有一致的接口
  • 逆鳞:无
  • 相关设计模式
    • 建造者模式:两者都是建造一批对象或者说产品,不同的是两者的目的和实现手段,在建造者模式中,是为了复用对象的构建过程而定义了一个指挥者,而在抽象工厂模式中,是为了提供一个这批对象的创建接口而定义了抽象工厂接口。

建造者模式

  • 设计原则:遵循单一职责、开闭原则
  • 常用场景:需要构建一批构建过程相同但表示不同的产品,而构建过程非常复杂
  • 使用概率:10%
  • 复杂度:中
  • 变化点:产品的表示
  • 选择关键点:各个产品的构建过程是否相同
  • 逆鳞:指挥者不能正常工作

原型模式

  • 设计原则:无
  • 常用场景:需要在运行时动态的创建指定实例种类的对象,或是需要复用其状态
  • 使用概率:10%
  • 复杂度:中低
  • 变化点:无
  • 选择关键点:创建出来的对象是否可以立即投入使用
  • 逆鳞:在以为是深度拷贝的情况下,却未实现深度拷贝

二.结构型设计模式

代理模式 

  • 设计原则:体现功能复用
  • 常用场景:需要修改或屏蔽某一个或若干个类的部分功能,复用另外一部分功能,可使用静态代理,若是需要拦截一批类中的某些方法,在方法的前后插入一些一致的操作,假设这些类有一致的接口,可使用JDK的动态代理,否则可使用cglib
  • 使用概率:99.99999%
  • 复杂度:中高
  • 变化点:静态代理没有变化点,动态代理的变化点为具有相同切入点的类
  • 选择关键点:静态代理选择的关键点是是否要复用被代理的部分功能,动态代理选择的关键点在于能否在将被代理的这一批类当中,找出相同的切入点
  • 逆鳞:切入点的不稳定
  • 相关设计模式
    • 适配器模式:对于适配器模式当中的定制适配器,它与静态代理有着相似的部分,二者都有复用功能的作用,不同的是,静态代理会修改一部分原有的功能,而适配器往往是全部复用,而且在复用的同时,适配器还会将复用的类适配一个接口

适配器模式

  • 设计原则:遵循开闭原则、体现功能复用
  • 常用场景:需要使用一个类的功能,但是该类的接口不符合使用场合要求的接口,可使用定制适配器,又或者是有一个接口定义的行为过多,则可以定义一个缺省适配器,让子类选择性的覆盖适配器的方法
  • 使用概率:40%
  • 复杂度:中
  • 变化点:无
  • 选择关键点:定制适配器的选择关键点在于是否有更加优良的替代方案,缺省适配器的选择关键点在于接口中的方法是否可以不全部提供,且都有缺省方案
  • 逆鳞:无
  • 相关设计模式
    • 装饰器模式:对于适配器模式中的定制适配器与装饰器模式,二者都是使用组合加继承的手段,不同的是,适配器模式的目的在于适配接口,装饰器模式的目的在于动态的添加功能,且可以叠加。

桥接模式

  • 设计原则:遵循单一职责、迪米特、开闭原则,体现功能复用
  • 常用场景:一个对象有多个维度的变化,需要将这些维度抽离出来,让其独立变化
  • 使用概率:20%
  • 复杂度:中高
  • 变化点:维度的扩展与增加
  • 选择关键点:是否可以将对象拆分成多个不相关的维度
  • 逆鳞:无

装饰器模式

  • 设计原则:遵循迪米特、单一职责、开闭原则,破坏里氏替换,体现功能复用
  • 常用场景:一个类需要动态的添加功能,且这些功能可以相互叠加
  • 使用概率:99.99999%
  • 复杂度:中
  • 变化点:动态添加的功能或者说装饰器
  • 选择关键点:添加的功能是否需要动态组装
  • 逆鳞:无

外观模式

  • 设计原则:遵循迪米特
  • 常用场景:一个子系统需要对外提供服务
  • 使用概率:60%
  • 复杂度:中
  • 变化点:无
  • 选择关键点:子系统对外提供服务是否需要依赖很多的类
  • 逆鳞:子系统对外提供的服务的变化或子系统本身的不稳定
  • 相关设计模式
    • 中介者模式:二者都是为了处理复杂的耦合关系,不同的是外观模式处理的是类之间复杂的依赖关系,中介者模式处理的是对象之间复杂的交互关系

组合模式

  • 设计原则:遵循依赖倒置、开闭原则,破坏接口隔离
  • 常用场景:当有一个结构可以组合成树形结构,且需要向客户端提供一致的操作接口,使得客户端操作忽略简单元素与复杂元素
  • 使用概率:30%
  • 复杂度:中
  • 变化点:节点的数量
  • 选择关键点:对外提供一致操作接口的结构是否可转化为树形结构
  • 逆鳞:结构不稳定或结构中的节点有递归关系

享元模式

  • 设计原则:无
  • 常用场景:一些状态相同的对象被大量的重复使用
  • 使用概率:90%
  • 复杂度:中
  • 变化点:无
  • 选择关键点:被共享的对象是否可以将外部状态提取出来
  • 逆鳞:没有将外部状态提取完全

行为型设计模式

观察者模式

  • 设计原则:遵循迪米特、开闭原则
  • 常用场景:需要将观察者与被观察者解耦或者是观察者的种类不确定
  • 使用概率:40%
  • 复杂度:中
  • 变化点:观察者的种类与个数
  • 选择关键点:观察者与被观察者是否是多对一的关系
  • 逆鳞:观察者之间有过多的细节依赖

模板方法模式

  • 设计原则:破坏里氏替换,体现功能复用
  • 常用场景:一批子类的功能有可提取的公共算法骨架
  • 使用概率:80%
  • 复杂度:中低
  • 变化点:算法骨架内各个步骤的具体实现
  • 选择关键点:算法骨架是否牢固
  • 逆鳞:无

策略模式

  • 设计原则:遵循单一职责、依赖倒置、迪米特、开闭原则
  • 常用场景:算法或者策略需要经常替换
  • 使用概率:60%
  • 复杂度:中
  • 变化点:策略的种类
  • 选择关键点:客户端是否依赖于某一个或若干个具体的策略
  • 逆鳞:无 

职责链模式

  • 设计原则:遵循迪米特
  • 常用场景:一个请求的处理需要多个对象当中的一个或几个协作处理
  • 使用概率:15%
  • 复杂度:中
  • 变化点:处理链的长度与次序
  • 选择关键点:对于每一次请求是否每个处理的对象都需要一次处理机会
  • 逆鳞:无

命令模式

  • 设计原则:遵循迪米特、开闭原则
  • 常用场景:行为的请求者与行为的处理者耦合度过高
  • 使用概率:20%
  • 复杂度:中高
  • 变化点:命令的种类
  • 选择关键点:请求者是否不需要关心命令的执行只知道接受者
  • 逆鳞:命令的种类无限制增长
  • 相关设计模式
    • 职责链模式:容易将二者关联在一起的原因是,二者都是为了处理请求或者命令而存在的,而且二者都是为了将请求者与响应者解耦,不同的是命令模式中,客户端需要知道一个命令的接受者,在创建命令的时候就把接受者与命令绑定在一起发送给调用者,而职责链模式中,客户端并不关心最终处理请求的对象是谁,客户端只是封装一个请求对象,随后交给职责链的头部而已,也正因为这样,二者的实现方式,有着很大的区别

状态模式

  • 设计原则:遵循单一职责、依赖倒置、开闭原则
  • 常用场景:一个对象在多个状态下行为不同,且这些状态可互相转换
  • 使用概率:20%
  • 复杂度:中
  • 变化点:状态的种类
  • 选择关键点:这些状态是否经常在运行时需要在不同的动态之间相互转换
  • 逆鳞:无
  • 相关设计模式
    • 策略模式:二者的实现方式非常相似,策略接口与状态接口,具体的策略与具体的状态以及二者都拥有的上下文,如果看它们的类图,会发现几乎一模一样,而二者不同的地方就在于,状态模式经常会在处理请求的过程中更改上下文的状态,而策略模式只是按照不同的算法处理算法逻辑,而且从实际场景来讲,顾名思义,状态模式改变的是状态,策略模式改变的是策略

解释器模式

  • 设计原则:遵循单一职责
  • 常用场景:有一种语言被频繁的使用
  • 使用概率:0.00009%
  • 复杂度:中高
  • 变化点:语言的规则
  • 选择关键点:被频繁使用的语言是否可用文法表示
  • 逆鳞:语言的规则无限制增长或规则十分不稳定

中介者模式

  • 设计原则:遵循迪米特,破坏单一职责
  • 常用场景:一个系列的对象交互关系十分复杂
  • 使用概率:10%
  • 复杂度:中
  • 变化点:对象之间的交互
  • 选择关键点:复杂的交互关系是否有共性可被中介者承担
  • 逆鳞:中介者无法工作

访问者模式

  • 设计原则:遵循倾斜的开闭原则
  • 常用场景:作用于一个数据结构之上的操作经常变化
  • 使用概率:5%
  • 复杂度:高
  • 变化点:数据结构之上的操作
  • 选择关键点:数据结构是否稳定以及操作是否经常变化
  • 逆鳞:数据结构的不稳定

备忘录模式

  • 设计原则:遵循迪米特、开闭原则
  • 常用场景:需要在对象的外部保存该对象的内部状态
  • 使用概率:5%
  • 复杂度:中
  • 变化点:无
  • 选择关键点:是否可以在必要的时候捕捉到对象的内部状态
  • 逆鳞:大对象的备份

迭代器模式

  • 设计原则:遵循迪米特
  • 常用场景:需要迭代访问一个聚合对象中的各个元素,且不暴露该聚合对象内部的表示
  • 使用概率:99.99999%
  • 复杂度:中
  • 变化点:聚合对象的种类
  • 选择关键点:客户端是否关心遍历的次序
  • 逆鳞:无
  • 相关设计模式
    • 访问者模式:二者都是迭代的访问一个聚合对象中的各个元素,不同的是,访问者模式中,扩展开放的部分在作用于对象的操作上,而迭代器模式中,扩展开放的部分在聚合对象的种类上,而且二者的实现方式也有着很大的区别。
posted on 2015-01-23 23:10  左手指月  阅读(147)  评论(0编辑  收藏  举报