《易学设计模式》-笔记

设计模式


创建型模式

 1. 简单工厂模式
 2. 工厂方法模式
 3. 抽象工厂模式
 4. 创建者模式
 5. 单例模式
 6. 原型模式

简单工厂模式又称静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例。而这些被创建的类有一个共同的父类,从而面向抽象编程。

类图:
simple factory1

优点:客户端不再负责对象的创建,而是把创建的责任丢给了具体的工厂类,客户端只负责对对象的调用,明确各个类的职责。
缺点:工厂使用静态方法来创建对象导致静态方法无法被继承。另外这个工厂类负责所有对象的创建,当具体产品不断增多需要不断修改工厂类增加相应判断逻辑不利于后期维护。

工厂方法模式简单工厂模式基础上继续进行职责的分配和包装。每一个产品都由一个具体的工厂来创建,把简单工厂模式中庞大的工厂类拆成一个个小的工厂类。每个具体的小工厂负责单独对象的创建,职责变小。

类图:
factory method
factory method

优点:如果有新的产品进入只需要新增一个创建产品工厂类和具体的产品类即可,不会影响到原来代码,增强系统拓展性。
缺点:需编写额外代码,增加了工作量。

抽象工厂模式工厂方法模式里每增加一种产品就需增加一个工厂类,即使两个产品有某些必要联系还是需要两个不同的工厂类。抽象工厂模式中每个工厂可以生产多个相关联的产品,即工厂方法模式里一个产品来自一个工厂类,而抽象工厂模式里多个产品来自一个工厂类。(适当减少工厂类的数目)

类图:
abstract factory
abstract factory

优点:当一系列相互关联的产品被设计到一个工厂类里,客户端的调用将会变得非常简单。而且如果要更换一系列的产品,只需要更换一个工厂类。
缺点:当有新的产品进来,需要修改抽象工厂类和具体工厂类的设计,需编写额外代码增加了工作量。

创建者模式抽象工厂模式里零件的组装放在客户端里导致客户端变得臃肿,但若把零件的组装放在具体的工厂类里又违反了工厂类单一职责的原则(同时负责产品的创建和组装)。创建者模式使用一个单独的类来负责产品的组装。

类图:
builder

优点:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,而且客户端不用知道对象的构建细节。组装的责任交给组装类,进一步明确各个类的职责。
缺点:产品之间差异非常大时,需要编写多个创建者类才能实现。

单例模式确保一个类只有一个实例并且该实例必须自动创建,具有唯一的全局访问点。

类图:
singleton

优点:客户端智能通过一个公共的调用点对类实例进行调用。
缺点:实现单例模式的类不能被别的类继承。

原型模式通过一个原型对象来表明要创建的类型,然后复制这个原型对象的方法来创建更多同类型的对象。

类图:
prototype

优点:可以动态地添加产品类而且对整体结构没有影响。
缺点:由于原型模式需要给每一个类都配备一个克隆的方法,这就需要在设计类时通盘考虑。因为在已有类的基础上添加clone操作比较困难。

小结

简单工厂模式可以看作工厂模式的一个特例,单例模式就是创建后只能有一个实例。找盖房子的建筑商就相当于使用了创建者模式;找生产砖头的工厂就相当于使用了工厂模式;找配钥匙的师傅就相当于使用原型模式

创建者模式抽象工厂模式的区别在于抽象工厂模式针对更细微的产品而创建,并且创建后产品的组装并不复杂。而创建者模式则是针对级别比较大的产品而创建,而且要创建产品的内部组装非常复杂。

builder

结构型模式

 1. 外观模式
 2. 适配器模式
 3. 代理模式
 4. 装饰者模式
 5. 桥模式
 6. 组合模式
 7. 享元模式

外观模式为对外提供一组接口的子系统提供一个统一的界面,使得其他系统对该系统的访问都通过这个统一的界面来完成。

类图:
facade

优点:通过统一对外接口访问系统,避免了外部系统和子系统之间的直接联系从而降低了系统间的依赖和复杂度。
缺点:限制了外部系统对子系统的灵活调用。

适配器模式外观模式通过统一的对外接口降低了系统之间的耦合度。当这个对外接口要被多个外部系统使用,因为各个系统需要方法返回数据的格式不同就需要进行适配。
适配器类分为对象适配器和适配器,对象适配器实现目标类的接口依赖适配者类,类适配器直接继承适配者类同时实现目标类的接口。

类图:
adapter

优点:通过提供统一对外接口访问系统,避免了外部系统和子系统之间的直接联系从而降低了系统间的依赖和复杂度。将一个系统的接口转换成另一种形式从而使原来不能直接调用的接口可以直接调用。
缺点:限制了外部系统对子系统的灵活调用。

代理模式代理模式就是给一个对象提供一个代理对象,由这个代理对象控制对原对象的引用,使代理类在客户端和原对象之间起到一个中介的作用。

类图:
proxy

优点:使用代理模式能够在不改变原来代码功能的基础上对某一对象进行额外的控制,是面向对象中单一职责的体现。
缺点:对于静态代理来说一个接口只服务于一种类型,如果要代理的方法很多则要为每一个方法定义一个接口。

装饰者模式额外地增加一个对象的一些功能,使用继承会造成子类爆炸,装饰者模式是继承的一个替代方案。使用被装饰类的一个子类的实例,在客户端将这个子类的实例委托给装饰类。

类图:
decorator

优点:装饰者模式能够提供比使用继承关系更加灵活的拓展对象的功能,它可以动态增加对象的功能并且可以随意组合这些功能。
缺点:使用装饰者模式进行设计往往会产生很多看上去相似的小对象。

桥模式多重继承使模型的抽象和它对应的实现耦合在一起,桥模式将抽象(抽象类及派生类)与其实现(抽象类和派生类实现自己的方式)解耦,使他们可以独立地变化。桥模式也是继承的一个替代方案。

类图:
bridge

优点:桥模式能提供比继承关系更灵活的功能,当有新的抽象或者实现方式时只需要集成一个抽象类或者一个实现即可。
缺点:如果重新抽象出另外一个类型,则需要修改抽象。

组合模式把部分和整体的关系用树形结构表示,从而使客户端能把一个一个的部分对象和由它们组合起来的整体对象采用同样方式处理。它也是继承的一个替代方案。

类图:
composite

优点:组合模式能提供比继承关系更灵活的功能,并且可以灵活组合子对象和父对象的关系从而使客户端的调用简单,客户端可以一致地使用组合结构或其中单个对象,简化了客户端代码。
缺点:很难限制向集合中添加的新组件的类型。

享元模式享元模式用来设计频繁使用又需要占用大量内存的对象。

类图:
flyweight

优点:节省空间。
缺点:如果需要维护的享元很多则查找的时候需要大量的时间,该模式以时间换空间。

 

行为型模式

 1. 模板方法模式
 2. 观察者模式
 3. 状态模式
 4. 策略模式
 5. 职责链模式
 6. 命令模式
 7. 访问者模式
 8. 调停者模式
 9. 迭代器模式
 10. 解释器模式

模板方法模式定义一个算法的骨架,而将具体的算法延迟到子类中实现。

类图:
template method

优点:灵活地实现具体的算法,满足用户灵活多变的需求。
缺点:算法骨架需要改变时需要修改抽象类。

观察者模式观察者模式是定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并自动更新。面向接口编程。当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象待改变或者说当一个对象必须通知其他对象而又不能假定其他对象是谁时需要使用该模式。

类图:
observer

优点:降低被观察者和观察者之间的耦合度,每一个具体观察者都实现一个相同的抽象观察者接口。观察者向被观察者注册,被观察者支持广播通信。
缺点:如果有多个观察者,通知所有观察者耗时较大。

状态模式根据对象状态不同有不同的行为。

类图:
state

优点:具体状态角色将具体状态和它对应的行为封装了起来,使得增加一种新状态很简单,不需要用复杂冗余的逻辑判断语句。
缺点:状态太多时,结构分散逻辑不太清楚。

策略模式定义一系列的算法,并将每一个算法封装起来使得它们可以相互替换。算法独立于使用它们的客户而变化。

类图:
strategy

优点:替换继承关系,避免使用多重条件转移语句。
缺点:客户端必须知道所有策略类,并自行决定使用哪一种策略类。如果算法较多,则会造成很多的策略类。

职责链模式使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求直到有一个处理它为止。

类图:
chain

优点:降低类之间的耦合度,使得处理类仅需要保持一个指向后继者的引用,也使得一个对象无需知道是其他哪一个对象处理其请求,对象仅需知道该请求会被正确处理。接收者和发送者都没有明确的对方信息,增强了给对象指派职责的灵活性。
缺点:因为对象不知道是其它哪一个对象处理其请求的,所以职责链模式不保证对象被接收。

命令模式命令模式就是把一个请求或者操作封装到一个对象中。它允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志可以很方便地实现撤消或恢复的功能。

类图:
command

优点:命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分隔开,从而使新的命令类可以很容易被加入到系统当中。
缺点:命令类较多时不便于管理。

访问者模式该模式表示一个作用于某对象结构中各元素的操作。使开发者可以在不改变各元素类的前提下作用于这些元素的新操作。

类图:
visitor

优点:使用访问者模式,对于原来的类层次增加新的操作只需要实现一个具体访问者角色,而不必改变整个类层次。每个具体的访问者角色都对应于一个相关操作。
缺点:不适合具体元素角色经常发生变化的情况。

调停者模式调停者模式就是用一个中介者对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其松散耦合,而且可以独立地改变它们之间的交互。

类图:
mediator

优点:当使用调停者模式时它将各个通信的对象解耦,使得原本分布在多个对象间的行为集中在一起,改变这些行为只需要生成新的协调类即可。便于维护拓展。
缺点:使控制集中化,因为所有的交互都集中在调停者类中。这个类变得复杂难管理。

备忘录模式该模式就是一个对象复制保存另外一个对象内部状态的对象。便于将对象状态恢复到原先保存的状态。

类图:
memento

优点:可以避免暴露一些应由源发器管理却又必须存储在源发器之外的信息。
缺点:开销大代价高。

迭代器模式该模式提供了一种顺序访问一个聚合对象中各元素而又不暴露该对象内部结构的方法。

类图:
iterator

优点:分离了集合对象的遍历行为,抽象出一个迭代器类来负责。
缺点:仅适用于访问容器。

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

类图:
interpreter

优点:容易修改和拓展语法,适用于文法简单并且对处理效率要求低的情况。
缺点:不适用于发杂文法的情况。

 

小结

代理模式是在访问对象时引入一定程度的间接性,因为这种间接性可以附加多种用途,实质上代理就是真实对象的代表。观察者模式中,主题的状态发生改变通知观察者改变,使得他们自己更新自己的行为。这样使得观察者不依赖于具体,而依赖于抽象。

模板模式策略模式应用场景类似但实现方式不同,前者使用继承后者使用委托。

设计原则


 1. 单一职责原则(SRP)-高内聚,低耦合
 2. 开闭原则(OCP)-一个对象对拓展开放,对修改关闭
 3. 里氏替换原则(LSP)-在任何父类出现的地方都可以用子类来代替
 4. 依赖注入原则(DIP)-要依赖抽象,不依赖于具体的实现
 5. 接口分离原则(ISP)-一个接口对外只提供一种功能,不强迫客户程序依赖它们不需要使用的方法
 6. 迪米特原则(LOD)-一个对象应当对其他对象尽可能少的了解
 7. 优先使用组合而不是继承原则(CARP)-继承时父类改变影响子类,组合时通过获得对其他对象的引用运行时动态定义

  1. All colorful pics are from 《Design Patterns》 By Jason McDonald.
posted @ 2014-05-24 17:02  Francis Fu  阅读(500)  评论(0编辑  收藏  举报