设计模式是一套被反复使用、让多数人知晓的、经过分类遍目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并保持代码可靠性。
创建型:主要用于描述如何创建对象
结构型:主要用于描述如何实现类或对象的组合
行为型:主要用于描述类或对象怎样交互以及怎样分配职责

面向对象设计原则:
总原则:开闭原则
软件实体对扩展开放,对修改关闭
单一职责原则:一个类只负责一个功能领域中的相应职责,当有多个职责时应该进行拆分
里氏替换原则:所有引用基类对象的地方能够透明地使用其子类的对象,LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范
依赖倒转原则:抽象不应该依赖于细节,细节应该依赖于抽象,面向接口编程,依赖抽象不依赖具体,代码交互中使用上层接口进行交互。
接口隔离原则:使用多个专门的接口,而不使用单一的总接口,使子类实现的每个方法都是有用的,如果不是,则需要拆分接口。
合成复用原则:尽量使用对象组合,而不是继承来达到复用的目的
迪米特法则(最少知道原则):一个软件实体应该尽可能减少与其他实体发生相互作用,无论依赖的类多么复杂,都应该将逻辑封装在内部,通过public方法提供给外部,当依赖的类发生变化时才能最小的影响该类。

创建型设计模式

1、简单工厂模式(Simple Factory)

属于对象创建型设计模式

概述

基本流程如下:首先将需要创建的各种不同对象的相关代码封装到不同的类中,这些类称为具体产品类,而将他们公共的代码进行抽象和提取后封装在一个抽象产品类中,每个具体产品类都是抽象产品类的子类;然后提供一个工厂类用于创建各种产品,在工厂类中提供一个创建产品的工厂方法,改方法可以根据所传入的参数不同创建不同的具体产品对象;客户端只需要调用工厂类的工厂方法并传入相应的产生即可得到一个产品对象

定义

定义一个工程类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都有公共的父类。在简单工厂模式中用于创建实例的方法是静态方法,因此简单工厂模式又被称为静态工厂方法

要点

当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无需知道创建细节

主要优点

1)工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除创建产品的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离。
2)客户端无需知道创建的具体产品类的类名,只需要知道具体产品类对应的参数即可,对于复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量

主要缺点

1)由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响
2)使用简单工厂模式势必会增加系统中类的个数,增加了系统复杂度和理解难度
3)系统扩展困难,一旦添加新产品就需要修改工厂逻辑,不利于维护
4)由于使用静态工厂方法,造成工厂角色无法形成基于基础的等级结构

适用场景

1)工厂类负责创建的对象比较少
2)客户端只知道传入工厂类的参数,对于如何创建对象并不关心

2、工厂模式(Factory)

属于对象创建型模式

概述

在简单工厂模式的基础之上,不再提供统一的工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构

定义

定义一个用于创建对象的接口,让子类决定将哪一个类实例化,工厂方法模式让一个类的实例化延迟到其子类,又可称为虚拟构造器模式或多台工厂模式

主要优点

1)在工厂方法模式中,工厂方法用来创建客户所需的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关系所需产品对应的工厂,无需关系创建细节,甚至无需知道具体产品的类名
2)基于工厂角色和产品角色的多态性设计是工厂模式的关键,它能够让工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部
3)使用工厂模式的另一个有的是在系统中加入新产品时,无需修改抽象工厂和抽象产品提供的接口,无需修改客户端,也无需修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了

主要缺点

1)添加新产品时,需要编写新的具体产品类,还需要新增具体工厂类
2)由于考虑系统扩展性,需要引入抽象层,在客户端代码中均使用抽象成进行定义,增加了系统的抽象性和理解难度

适用场景

1)客户端不知道它所需要的对象的类,只知道所对应的工厂
2)抽象工厂类通过其子类来指定创建哪个对象,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来明确具体要创建的对象

3、抽象工厂模式(Abstract Factory)

属于对象创建型模式

概述

为创建一组对象提供了一种解决方案

定义

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

主要优点

1)隔离了具体类的生成,使得客户并不知道什么被创建,只需要替换工厂实例,就可以修改整个系统行为
2)当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的产品。

主要缺点

1)增加产品等级结构麻烦,需要进行较大修改

适用场景

1)一个系统不应该依赖于产品类实例如何被创建、组合和表达的细节
2)系统中有多于一个的产品族,每次只使用其中一个产品族
3)属于同一个产品族的产品将在一起使用,
4)产品等级结构稳定,设计完成后不会新增或者删除已有的等级结构

4、单例模式(Singleton)

属于对象创建型模式

定义

确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类

要点

1)只有有一个实例
2)必须自行创建这个实例
3)必须自行向整个系统提供这个实例

主要优点

1)提供对唯一实例的受控访问
2)由于只有一个实例对象,可以节省空间
3)允许可变数目的实例

只要缺点

1)由于单例没有抽象层,因此扩展不方便
2)单例职责过重,一定程度违背单一职责原则

适用场景

1)系统只需要一个实例对象,如果系统要求提供一个唯一的序列号生成器或资源管理器
2)客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例

5、原型模式(Prototype)

属于对象创建型模式

概述

使用时首先需要创建一个原型对象,再通过复制这个原型对象来创建更多同类型对象

定义

使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象

主要优点

1)当创建新的对象实例比较复杂时,可以使用原型模式
2)扩展性较好,由于在原型模式中提供了抽象原型类,在客户端可以针对抽象原型类进行编程
3)原型模式提供了简化的创建结构,原型模式中产品的复制是通过封装在原型类中的克隆方法实现的,无需专门的工厂类来创建产品
4)可以使用深克隆的方式保存对象的状态

主要缺点

1)需要为每个类配备一个克隆方法
2)实现深克隆时需要编写较为复杂的代码

适用场景

1)创建新对象成本较大
2)如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占用内存较少时,可以使用原型模式配合备忘录模式来实现
3)需要避免使用分层次的工厂类来创建分层次的对象

6、建造者模式(Builder)

属于对象创建型模式

概述

是较为复杂的创建型模式,它将客户端与包含多个组成部分的复杂对象的创建过程分离,客户端无需知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可

定义

将一个复杂对象的构建与它的表示分离,使得统一的构建过程可以创建不同的表示

主要优点

1)客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以长久不同的产品对象。
2)每个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者
3)可以更加精细地控制产品的场景过程,将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰

主要缺点

1)如果产品差异很大,不适合使用
2)如果产品内部编号复杂,可能会导致需要定义很多具体建造者类来实现这种变化

适用场景

1)需要生成的产品对象有复杂的内部结构
2)需要生成的产品对象的属性相互依赖,需要指定其生成顺序
3)对象的创建过程独立于创建该对象的类
4)隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。

结构型模式

1、适配器模式(Adapter)

概述

在适配器模式中引入了一个称为适配器的包装类,而它所包装的对象称为适配者,适配器让那些由于接口不兼容而不能交互工作的类可以一起工作,既可以作为类结构型模式,也可以作为对象结构型模式

定义

将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(wrapper),

主要优点

1)将目标类和适配者类解耦,通过引入一个适配器来重用现有的适配者类,无需修改原有结构
2)增加了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性,用一个适配者类可以在多个不同的系统中复用
3)灵活性和扩展性都非常好
类适配器模式还有如下优点:
由于适配器类是适配者的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强
对象适配器还有如下优点:
1)一个对象适配器可以把多个不同的适配者适配到同一个目标
2)可以适配一个适配者的子类,由于适配器和适配者之间是关联关系,根据“里氏代换原则”,适配者的子类也可通过该适配器进行适配

主要缺点

类适配器模式的缺点:
1)适配类不能为最终类,在java中不能为final类,C#中不能为sealed类
2)对于java、C#等不支持多重继承的语言,一次最多只能适配一个适配者类
3)在java、C#等语言中,类适配器模式中的目标抽象类只能为接口,不能为类
对象适配器模式的缺点:
与类适配器模式相比,要在适配器中置换适配者类的某些方法比较麻烦

适用场景

1)系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码
2)想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作

2、桥接模式(bridge)

概述

桥接模式是一种很实用的结构型设计模式,如果软件系统中某个类存在两个独立变化的维度,通过该模式可以将这两个维度分离出来,使两者可以独立扩展,与多层继承方案不同,它将两个独立变化的维度设计为两个独立的继承结构的桥,故名桥接模式。

定义

将抽象部分与它的实现部分分离,使他们都可以独立地变化。它是一种对象结构模式,又称为柄体模式(handle and body)或者接口模式(interface)

主要优点

1)分离抽象接口及其实现部分
2)在很多情况下可以取代多层继承方案
3)提供了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统

主要缺点

1)会增加系统的设计和理解难度,需要一开始就针对抽象层进行设计于编程
2)要求正确识别出系统中两个独立变化的维度,使用范围有一定局限性,识别出两个独立维度也需要一定的经验积累

适用场景

1)如果需要在抽象化和具体化之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系
2)抽象部分和实现部分可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合
3)一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展
4)对应那些不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统

3、组合模式(composite)

概述

组合模式可以让叶子对象和容器对象的使用具有一致性

定义

组合多个对象形成树形接口以表示具有“整体-部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体-部分”(part-whole)模式,是一种对象结构型模式

主要优点

1)组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
2)客户端可以一致地使用一个组合结构或其中单个对象,不必关系处理的是单个对象还是整个组合结构,简化了客户端代码
3)在组合模式中增加新的容器构件和叶子构件都很方便,无须对现有类库进行任何修改
4)增加新构件很难对容器中的构建类型进行限制,有时候我们希望一个容器只能有某些特定类型的对象,例如在某个文件夹中只能包含文本文件,使用组合模式时,不能依赖类型系统来施加这些约束,因为他们都来自于形态的抽象层,在这种情况下,必须通过在运行时进行类型检查来实现,这个实现过程较为复杂。

适用场景

1)在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致地对待他们
2)在一个使用面向对象语言开发的系统中需要处理一个树形结构
3)在一个系统中能够分离出叶子对象和容器对象,而且他们的类型不固定,需要增加一些新的类型

4、装饰模式(Decotator)

属于对象结构型模式

概述

装饰模式可以在不改变一个对象本身功能的基础上给对象证件额外的新行为,在现实生活中,这种情况也导出存在

定义

动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活

主要优点

1)对于扩展一个对象的功能,装饰器模式比继承更加灵活
2)可以同一种动态的方式来扩展一个对象的功能
3)可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,得到功能更为强大的对象
4)具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类

主要缺点

1)会产生很多小对象,这些小对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值不同
2)排错困难,对于多次装饰的对象,调试时寻找错误可能需要诸暨排查

适用场景

1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
2)当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰器模式

5、外观模式(Facade)

概述

在软件开发中,有时候为了完成一项较为复杂的功能,一个客户端需要合多个业务类交互,而这些需要交互的业务类经常会作为一个整体出现,由于涉及类比较多,导致使用时代码较为复杂,此时,特别需要一个类似服务员一样的角色,由它来复杂和多个业务类进行交互,而客户类只需要与该类交互

定义

为子系统中的一组接口提供一个统一的入口,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用

主要优点

1)它对客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易。
2)它实现了子系统与客户端之间的松耦合关系,这使得子系统的变化不会影响到调用它的客户端,只需要调整外观类即可
3)一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象

主要缺点

1)不能很好地限制客户端之间使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性
2)如果涉及不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则

适用场景

1)当要为访问一系列复杂的子系统提供一个简单入口时可以使用外观模式
2)客户端程序与多个子系统之间存在很大的依赖性,引入外观类可以将子系统与客户端解耦,从而提高子系统的独立性和可移植性
3)在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类简历联系,降低层之间的耦合度

6、享元模式(Flyweight)

属于对象结构型模式

概述

当一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等问题。享元模式通过共享技术实现相同或相似对象的重用,以共享的方式高效地支持大量细粒度对象的重用,享元对象能做到共享的关键是区分了内部状态和外部状态:
1)内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,内部状态可以共享
2)外部状态是随环境改变而改变的、不可以共享的状态

定义

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

主要优点

1)可以极大减少内存中对象的数量,使得相同或相似对象在内存中只保存一份,从而节约系统资源,提高系统性能
2)享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享

主要缺点

1)享元模式使得系统变得复杂,需要分离内部状态和外部状态
2)为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使运行时间变长

适用场景

1)一个系统有大量相同或者相似的对象
2)对象的大部分状态都可以外部化,可以将这些外部状态传入对象中
3)在使用享元模式时需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源,因此、应当在需要多次重复使用享元对象时才值得使用享元模式

7、代理模式(proxy)

属于对象结构型设计模式

概述

由于某些原因,客户端不想或不能直接访问一个对象,次数可以通过一个称之为“代理”的第三者来实现间接访问,常用的几种代理模式:
1)远程代理(Remte Proxy):为一个不同的地址空间的对象提供一个本地的代理对象
2)虚拟代理(Virtual Proxy):如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建
3)保护代理(Protect Proxy):控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限
4)缓冲代理(Cache Proxy):为某一个目标操作的结果提供临时的存储空间,一遍多个客户端可以共享这些结果
5)智能引用代理(Smart Reference Proxy):当一个对象被引用时,提供一些额外的操作,例如将对象被调用的次数记录下来

定义

给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问

主要优点

1)能够协调调用者和被调用者,在一定程度上降低了系统的耦合度
2)客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源代码,符合开闭原则,系统具有较好的灵活性和可扩展性。
3)远程代理为位于两个不同地址空间对象的访问提供了一种实现机制,可以将一些消耗资源较多的对象和操作移至性能更好的计算机上,提供系统整体运行效率
4)虚拟代理通过消耗资源较少的对象来代表一个消耗资源较多的对象,可以在一定程度上节省系统的运行开销
5)缓冲代理为某一个操作的结果提供临时的缓存存储空间,以便在后续使用中能够共享这些结果,欧化系统性能,缩短执行时间
6)保护代理可以控制对一个对象的访问权限,为不同用户提供不同级别的使用权限

主要缺点

1)由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求处理速度变慢
2)实现代理模式需要额外的工作,而有些代理模式的实现过程较为复杂,例如远程代理

适用场景

1)当客户的对象需要访问远程主机中的对象时可以使用远程代理
2)当需要用一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、缩短运行时间时可以使用虚拟代理,例如一个对象需要很长时间才能完成加载
3)当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以提供多个客户端共享访问这些结果时可以使用缓冲代理
4)当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时可以使用保护代理
5)当需要为一个对象的访问(引用)提供一些额外的操作时可以使用智能引用代理

十一个行为模式

1、职责链模式(Chain of Responsibility)

属于对象行为型模式

概述

很多情况下、在一个软件系统中可以处理某个请求的对象不止一个,这些可处理的对象沿着这条链传递,这条链就称为职责链

定义

避免请求发送者与接收者耦合在一起,让多个对象有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止

主要优点

1)职责链模式使得一个对象无须直到是其他哪一个对象处理其请求,对象仅需知道该请求会被处理即可,接收者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统耦合度
2)请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,可简化对象的相互连接
3)在给对象分派职责时,职责链可以给我们更多的灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责
4)在系统中增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可,从这一点来看是符合“开闭原则”的

主要缺点

1)由于一个请求没有明确的接收者,那么久不能保证它一定会被处理,有可能直到最后也得不到处理,或者是没有正确配置而得不到处理
2)对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能会受影响
3)如果建链不当,可能会造成循环调用,导致死循环

适用场景

1)有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定,客户端只需将请求提交到链上,而无须关心请求的处理对象是谁
2)在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
3)可动态指定一组对象处理请求,客户端可以动态创建职责链来处理请求,还可改变链中处理者之前的先后顺序

2、命令模式(Command)

属于对象行为型模式,也称动作(Action)模式或者事务(Transaction)模式

概述

在软件开发中,我们经常需要向某些对象发送请求(调用其中的方法),但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,此时,我们特别希望能够以一种松耦合的方式来设计软件,使得请求发送者和请求者能够消除彼此之间的耦合,让对象之间的调用关系更加灵活

定义

将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化;对请求牌堆或者记录请求日志,以及支持可超限的操作

主要优点

1)降低系统的耦合度
2)新的命令很容易地加入到系统中
3)可以比较容易地设计一个命令队列或宏命令(组合命令)
4)为请求的撤销和恢复操作提供了一种设计和实现方案

适用场景

1)系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互
2)系统需要在不同的时间指定请求、将请求排队和执行请求
3)系统需要支持命令的撤销操作和恢复操作
4)系统需要将一组操作组合在一起形成宏命令

3、解释器模式(Interpreter)

属于类行为模式

概述

解释器模式是一种使用频率相对较低但学习难度较大的设计模式,它用于描述如何使用面向对象语言构成一个简单的语言解释器

定义

定义一个语言的文法,并且建立一个解释器来解释该语言中的句子,这里的“语言”是指使用规定格式和预发的代码

主要优点

1)易于改变和扩展文法
2)每一条文法规则都可以表示为一个类
3)实现文法较为容易
4)增加新的解释表达式较为方便

主要缺点

1)对应复杂文法难以维护
2)执行效率较低

适用场景

1)可以将一个需要解释执行的语言中的句子表示为一个抽象语法树
2)一些重复出现的问题可以用一种简单的语言来进行表达
3)一个语言的文法较为简单
4)执行效率不是关键问题

4、迭代器模式(Iterator)

属于对象行为模式

概述

在软件开发中,我们经常需要使用聚合对象来存储一系列数据。聚合对象有两个职责:一是存储数据;二是遍历数据

定义

提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)

主要优点

1)它支持以不同的反射遍历一个聚合对象,在同一个聚合对象上可以订阅多种遍历方式
2)迭代器简化了聚合类
3)在迭代器模式中,由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码

主要缺点

1)由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类
2)抽象迭代器的设计难度较大,需要充分考虑到系统将来的扩展

适用场景

1)访问一个聚合对象的内容而无须暴露它的内部表示
2)需要为一个聚合对象提供多种遍历方式
3)为遍历不同的聚合结构提供一个统一的接口,在该接口的实现类中为不同的聚合结构提供不同的遍历方式,而客户端可以一致性地操作该接口

5.中介者模式(Mediator)

属于对象行为模式

概述

如果在一个系统中对象之间的联系呈现为网状结构,对象之间存在大量的多对多联系,这种相互作用表现为一个对象与另外一个对象的直接耦合,这将导致一个过渡耦合的系统

定义

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

主要优点

1)中介者模式简化了对象之间的交互,它用中介者和同事的一对多交互代替了原来的同事之间的多对多交互,一对多关系更容易理解、维护和扩展,将原本难以理解的网状结构转换成相对简单的星型结构
2)中介者描述可将各同事对象解耦,
3)可以减少子类生成,中介者将原本分布于多个对象间的行为集中在一起,改变这些行为只需生成新的中介者子类即可,这试各个同事类可被重用,无须对同事类进行扩展

主要缺点

1)在具体中介者类中包含了大量同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。

适用场景

1)系统中对象间存在复杂的引用关系,系统结构混乱且难以理解
2)一个对象由于引起了其他很多对象并且直接合这些对象通信,导致难以复用改对象
3)想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类

6、备忘录模式(Memento)

属于对象行为模式,别名为Token

概述

备忘录模式提供了一种恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当心的状态无效或者存在问题时,可以使用展示存储起来的备忘录将状态复原,当前很多软件都提供了撤销操作,其中就是使用了备忘录模式

定义

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

主要优点

1)它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原
2)备忘录实现了对信息的封装,一个备忘录对象是一种原发器对象状态的表示,不会被其他代码所改动

主要缺点

1)资源消耗过大,如果需要保存的原发器类的成员变量太多,就不可避免需要占用大量的存储空间,每保存一次对象的状态都需要消耗一定的系统资源

适用场景

1)保存一个对象在某个时刻的全部状态或部分状态,这样以后需要时它能够恢复到先前的状态,实现撤销
2)防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态的实现细节暴露给外界对象

7、观察者模式(Observer)

属于对象行为模式,别名包括发布-定义(publish/Subscribe),模型-视图(model/view),源-监听器(source/Listener),从属者(dependents)模式

概述

它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将作出相应反应。发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以有多个观察者,而且观察者直接可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展

定义

定义对象之间的一种一对多的依赖关系,使得每当一个对象状态发送改变时,其相关依赖对象皆会得到通知并被自动更新。

主要优点

1)观察者模式可以实现表示层和数据逻辑层的分离,定义了稳定的消息更新传递机制,并抽象了更新接口,使得可以有各种各样不同的表示层充当具体观察者角色
2)观察者模式在观察目标和观察者之间建立一个抽象的耦合
3)观察者模式支持广播通信,观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度
4)观察者模式满足“开闭原则”的要求,增加新的具体观察者无须修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下增加新的观察目标也很方便

主要缺点

1)如果一个观察目标对象有很多直接和间接观察者,将所有的观察者都通知到会花费很多时间
2)如果在观察者和观察目标直接存在循环依赖,观察目标会触发它们之间进行循环调用,可能导致系统崩溃
3)观察者模式没有响应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅知道观察目标发生了变化

适用场景

1)一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立的对象中使它们可以各自独立地改变和复用
2)一个对象的改变将导致一个或多个其他对象也发送改变,而不知道具体有多少对象将发送改变,也不知道这些对象是谁
3)需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象

8、状态模式(State)

属于对象行为型模式

概述

状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。当系统中某个对象存在多个状态,这些状态直接可以进行转换,而且对象在不同状态下行为不相同时可以使用状态模式。状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化,对于客户端而已,无须关心对象状态的转换以及对象所处的当前状态,无论对于何种状态的对象,客户端都可以一致处理。

定义

运行一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类

主要优点

1)封装了状态的转换规则,在状态模式中可以将状态的转换代码封装在环境类或者具体状态类中,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中
2)将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为
3)允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块,状态模式可以让我们避免使用庞大的条件语句来讲业务方法和状态转换代码交织在一起
4)可以让多个环节对象共享一个状态对象,从而减少系统中对象的个数

主要缺点

1)状态模式的使用比如会增加系统中类和对象的个数,导致系统运行开销增大
2)状态模式的结构与实现都较为复杂,如果使用不当讲导致程序结构和代码的混乱,增加系统设计的难度
3)状态模式对“开闭原则”支持并不友好,增加新的状态类需要修改那些负责状态转换的源代码

适用场景

1)对象的行为依赖于它的状态
2)在代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强。

9、策略模式(Strategy)

属于对象行为模式

概述

在策略模式中,我们可以订阅一些独立的类来封装不同的算法,没一个类封装一种具体的算法,在这里,每个封装汇的类我们都可以称之为一种策略,为了保证这些策略在使用时具有一致性,一般会提供一个抽象的策略类来做规则的定义,而每种算法则对应于一个具体策略类。

定义

定义一系列算法类,将每一个算法封装起来,并让他们可以相互替换,策略模式让算法独立于使用它的客户而变化,将每一个算法封装起来,并让他们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)

主要优点

1)策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为
2)策略模式提供了管理相关的算法族的办法
3)策略模式提供了一种可以替换继承关系的办法。
3)使用策略模式可以避免多重条件选择语句
4)策略模式提供了一种算法的复用机制,由于将算法单独提取出来封装在策略类中,因此不同的环境类可以方便地复用这些策略类。

主要缺点

1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类
2)策略模式将造成系统产生很多具体策略类,任何细小的变化都讲导致系统要增加一个新的具体策略类
3)无法同时在客户端使用多个策略类,也就是锁,在使用策略模式时,客户端每次只能使用一个策略类,不支持使用一个策略类完成部分功能后再使用另一个策略类来完成剩余功能的情况

适用场景

1)一个系统需要动态地在几种算法中选择一种,name可以将这些算法封装到一个个小的具体算法类中,而这些具体算法类都是一个抽象算法类的子类。
2)一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重条件选择语句类实现。
3)不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法与相关的数据结构,可以提供算法的保密性和安全性。

10、模板方法模式(Template Methed)

概述

在软件开发中,某个方法的实现需要多个步骤,其中有些步骤是固定的,而有些步骤并不固定,存在可变性。为了提供代码的复用性和系统的灵活性,可以使用一种称之为模板方法模式的设计模式来对这类情况进行设计,在模板方法模式中,将实现功能的每一个步骤锁对应的方法称为基本方法,而电影这些基本方法同上定义基本方法的执行次小的方法称为模板方法。

定义

定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义改算法的某些特定步骤

主要优点

1)在父类中形式化地定义一个算法,而由它的子类来实现细节的处理
2)模板方法模式是一种代码复用技术,它在类库设计中尤为重要,它提取了类库中的公共行为,将公共行为放在父类中,而通过其子类来实现不同的行为,它鼓励我们恰当使用继承来实现代码复用
3)可实现一种反向控制结构,通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行
4)在模板方法模式中可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则

主要缺点

1)需要为每一个基本方法的不同实现提供一个子类,如果父类中可变的基本方法太多,将会导致类的个数增加,系统更加庞大,设计也更加抽象,此时,可结合桥接模式来进行设计。

适用场景

1)对一些复杂的流程进行分割,将其流程中固定不变的部分设计为目标方法和父类具体方法,而一些可以改变的细节由其子类来实现。
2)各子类中公共的行为应该被提取出来并收集到一个公共父类中以避免代码重复
3)需要通过子类来决定父类流程中某个步骤是否执行,实现子类对父类的反向控制

11、访问者模式(Visitor)

属于对象行为型模式

概述

访问者模式是一种较为复杂的行为型设计模式,它包含访问者和被访问者元素两个主要组成部分,这些被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作

定义

提供一个作用于某对象结构中的各元素的操作表示,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作

主要优点

1)增加新的访问操作很方便。
2)将有关元素对象的访问行为集中到一个访问对象中,而不是分散在一个个的元素类中。
3)让用户能够在不修改现有元素类层次结构的情况下,定义作用于该层次结构的操作。

主要缺点

1)增加新的元素,类很困难。
2)破坏封装。

适用场景

1)一个对象结构包含多个类型的对象,希望对这些对象实施一些依赖其具体类型的操作。
2)需要对一个对象结构中的对象进行很多不同的并且不相干的操作。
3)对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作