二十三种设计模式修炼手册


不知不觉,在开发这条道路上摸爬打滚也有些年头了,偶尔回头看看之前写的代码,真可谓粗糙至极。固然了,那时候仍是小白,代码写得难看些情有可原,不过如今可不能再用之前的标准去衡量本身了,所以掌握一些高级架构技巧是必须的,设计模式正是一个很好的敲门砖。html

在我看来,设计模式不只仅只是一套模板,要想掌握设计模式并作到触类旁通,必须深刻理解其中的思想,这个模式是为了解决什么问题?解决的思路是什么?代码的实现又如何?若是问题细节发生了微小的变化又该如何处理?因此说思考很重要,不能死记硬背,必定要多想。算法

写下这篇文章,是为了梳理本身的知识点,作个记录。若是有来人看到了,而且对你有帮助的话,我也会很开心,由于知识是要传播的,你们都乐于分享本身的看法,才能共同进步。编程


设计模式的定义

模式一词起源于建筑业,描述了解决问题的核心方法。经过这种方式,能够屡次重用那些已有的解决方案,无须重复相同的工做。设计模式

模式能够应用于不一样的领域,软件模式是将模式的通常概念应用于软件开发领域,能够被认为是对软件开发中某一特定问题的解法的某种统一表示。软件模式并不是仅限于设计模式,还包括架构模式、分析模式和过程模式等,在软件生存期的每个阶段都存在着一些被认同的模式。架构

在软件模式领域,目前研究最深刻的是设计模式。设计模式是一套被反复使用、多数人知晓的、通过分类编目的、代码设计经验的总结,使用这些设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。函数


设计模式的基本要素

设计模式通常有以下几个基本要素:模式名称、问题、目的、解决方案、效果、实例代码和其余相关设计模式,其中的关键元素包括如下四个方面:学习

模式名称:经过一两个词来描述模式的问题、解决方案和效果,以更好地理解模式并方便开发人员之间的交流。this

问题:描述了应该在什么时候使用模式,它包含了设计中存在的问题以及问题存在的缘由。有时候问题描述可能会包含使用该模式时必须知足的一系列先决条件。spa

解决方案:描述了设计模式的组成部分,以及这些组成部分之间的相互关系,各自职责和协做方式。解决方案并不描述一个特定而具体的设计或实现,而是提供设计问题的抽象描述和怎样用一个具备通常意义的元素组合(类或者对象)来解决这个问题。设计

效果:描述模式应有的效果以及在使用模式时应权衡的问题。效果主要包含模式的优缺点分析,所以须要综合考虑模式的效果。


设计模式的分类

设计模式通常有两种分类方式,一种是根据目的分类(模式是用来作什么的),另外一种则是根据范围分类(模式是用来处理类之间的关系仍是处理对象之间的关系)。根据这两种分类分别有以下两张表供参考:


范围\目的 建立型模式 结构型模式 行为型模式
类模式 工厂方法模式 (类)适配器模式 解释器模式
模板方法模式
对象模式 抽象工厂模式
建造者模式
原型模式
单例模式
(对象)适配器模式
桥接模式
组合模式
装饰模式
外观模式
享元模式
代理模式
职责链模式
命令模式
迭代器模式
中介者模式
备忘录模式
观察者模式
状态模式
策略模式
访问者模式

下面简单对二十三种设计模式进行说明


模式类别 模式名称 模式说明
建立型模式
抽象工厂模式 提供了一个建立一系列相关或相互依赖对象的接口,而无须指定它们具体的类
工厂方法模式 该类的实例化操做延迟到子类中完成,即由子类来决定究竟该实例化(建立)哪个类
建造者模式 将一个复杂对象的构建与它的表示分离,使得一样的构建过程能够建立不一样的表示
原型模式 经过给出一个原型对象来指明要建立对象的类型,而后经过复制这个原型对象来建立更多同类型的对象
单例模式 确保在系统中某一个类只有一个实例,能够自行实例化并向整个系统提供这个实例
结构型模式
适配器模式 将一个接口转换成客户但愿的另外一个接口,从而使接口不兼容的那些类能够一块儿工做
桥接模式 将抽象部分与它的实现部分分离,使它们均可以独立地变化
组合模式 组合多个对象造成树形结构以表示“总体-部分”的结构层次
装饰模式 动态地给一个对象增长一些额外的职责
外观模式 为复杂子系统提供一个一致的接口
享元模式 经过运用共享技术有效地支持大量细粒度对象的复用
代理模式 给某一个对象提供一个引用,并由代理对象控制对原对象的引用
结构型模式
职责链模式 避免请求发送者与接收者耦合在一块儿,让多个对象都有可能接收请求,将这些对象链接成一条链,而且沿着这条链传递请求,直到有对象处理为止
职责链模式 避免请求发送者与接收者耦合在一块儿,让多个对象都有可能接收请求,将这些对象链接成一条链,而且沿着这条链传递请求,直到有对象处理为止
命令模式 将一个请求封装为一个对象,从而使得请求调用者和请求接收者解耦
解释器模式 描述如何为语言定义一个语法,如何在该语言中表示一个句子,以及如何解释这些句子
迭代器模式 提供了一种方法来访问聚合对象,而不用暴露这个对象的内部表示
中介者模式 经过一个中介对象来封装一系列的对象交互,使得各对象不须要显式地相互引用,从而使其耦合松散,并且能够独立地改变它们之间的交互
备忘录模式 在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象以外保存这个状态,这样能够在之后将对象恢复到原先保存的状态
观察者模式 定义了对象间的一种一对多依赖关系,使得当每个对象状态发生改变时,其相关依赖对象皆获得通知并被自动更新
状态模式 容许将一个对象在其内部状态改变时改变它的行为
策略模式 定义一系列算法,并将每个算法封装在一个类中,让它们能够相互替换,策略模式让算法独立于使用它的客户而变化
模板方法模式 定义一个操做中算法的骨架,而将一些步骤延迟到子类中
访问者模式 表示将一个做用于某对象结构中的各元素操做,它使得用户能够在不改变各元素的类的前提下定义做用于这些元素的新操做

软件设计模式修炼 -- 简单工厂模式
软件设计模式修炼 -- 工厂方法模式
软件设计模式修炼 -- 抽象工厂模式
软件设计模式修炼 -- 建造者模式
软件设计模式修炼 -- 原型模式
软件设计模式修炼 -- 单例模式
软件设计模式修炼 -- 适配器模式
软件设计模式修炼 -- 桥接模式
软件设计模式修炼 -- 组合模式
软件设计模式修炼 -- 装饰模式
软件设计模式修炼 -- 外观模式
软件设计模式修炼 -- 享元模式
软件设计模式修炼 -- 代理模式
软件设计模式修炼 -- 职责链模式
软件设计模式修炼 -- 命令模式
软件设计模式修炼 -- 解释器模式
软件设计模式修炼 -- 迭代器模式
软件设计模式修炼 -- 中介者模式
软件设计模式修炼 -- 备忘录模式
软件设计模式修炼 -- 观察者模式
软件设计模式修炼 -- 状态模式
软件设计模式修炼 -- 策略模式
软件设计模式修炼 -- 模板方法模式
软件设计模式修炼 -- 访问者模式


以上就是设计模式的简单介绍,下面是一些补充知识,若是已经掌握了能够不看。这些知识虽然不属于设计模式范畴,但对于咱们理解设计模式有莫大的好处。


统一建模语言

统一建模语言(UML)是一种可视化的标准建模语言,经过UML能够构造软件系统的蓝图。在设计模式中,使用UML来分析和设计每个模式的结构,描述每个模式实例,帮助咱们深刻理解设计模式。

好比要盖一栋房子,须要先设计图纸,设计图纸就是一种设计语言,也就是模型语言。在一个现代化工程中,人们要沟通和协做,就必须使用标准的工业化设计语言,经过建模进行描述,把所要设计的结构和系统的行为联系起来,对系统的结构进行可视化控制。


UML 结构

UML 是由图形符号表达的建模语言,其主要包括如下几个部分:

视图

使用不一样的视图从不一样角度来描述软件系统,包括:

用户视图:以用户观点表示系统的目标,它是全部视图的核心,该视图描述系统的需求

结构视图:表示系统的静态行为和静态元素,如包、类与对象,以及它们之间的关系

行为视图:表示系统的动态行为,描述组成元素如对象在系统运行时的交互关系

实现视图:表示系统中逻辑元素的分布,描述系统中物理文件以及它们之间的关系

环境视图:表示系统中物理元素的分布,描述系统中硬件设备以及它们之间的关系

提供了十三种与上述五种视图相对。在设计模式的学习中,重点关注类图、顺序图和状态图便可。

用例图:对应用户视图。在用例图中,使用用例来表示系统的功能需求,用例图表示多个外部执行者与系统用例之间以及用例与用例之间的关系。

类图:对应于结构视图。类图使用类来描述系统的静态结构,类图包括类和它们之间的关系。

对象图:对应于结构视图。对象图用于表示类的对象实例之间的关系。

包图:对应于结构视图。描述包与包之间的关系。

组合结构图:对应于结构视图。表示一个类的内部结构。

状态图:对应于行为视图。描述一系列对象的状态及状态之间的转换。

活动图:对应于行为视图。表示系统中各类活动的次序。

顺序图:又称时序图或序列图,对应于行为视图。表示对交互,重点表示对象之间发送消息的时间顺序。

定时图:对应于行为视图。定时图采用一种带数字刻度的时间轴来描述消息的顺序,相比顺序图来讲更加精确。

交互概览图:对应于行为视图。能够把交互概览图理解为细化的活动图,在其中的活动都经过一些小型的顺序图来表示。

组件图:又称构件图,对应于实现视图。描述每一个功能所在组件位置以及它们之间的位置。

部署图:又称实施图,对应于环境视图。描述软件中各个组件驻留的硬件位置以及这些硬件之间的交互关系。

模型元素

模型元素包括事物以及事物之间的联系。事物表明任何能够定义的东西,事物之间的关系把事物联系在一块儿,组成有意义的结构模式

通讯机制

为模型元素提供额外的注释、修饰和语义。


面向对象设计原则

面向对象设计原则是学习设计模式的基础,每一种设计模式都符合某一种或多种面向对象设计原则。在软件开发中使用这些原则能够提升软件的可维护性和可复用性,让咱们能够设计出更加灵活也更容易扩展的软件设计,实现可维护性复用的目标。

单一职责原则

一个对象应该只包含单一的职责,而且该职责被完整地封装在一个类中

一个类承担的职责越多,被复用的可能性越小,而且至关于将这些职责耦合在一块儿。所以须要将这些职责进行分离,实现高内聚、低耦合的指导方针。

开闭原则

一个软件实体应当对扩展开放,对修改关闭。也就是说在设计一个模块,应当使这个模块能够在不被修改的前提下被扩展。

在开闭原则的定义中,软件实体能够是一个软件模块、一个由多个类组成的局部结构或一个类。

软件的需求会随着时间推移发生变化,若是软件设计符合开闭原则,就能够在扩展时无须修改现有代码,保证稳定性与延续性。

抽象化是知足开闭原则的关键,经过定义一个相对稳定的抽象层,将不一样的实现行为在具体实现层中实现。若是须要修改,无须改动抽象层,只需增长新的实体类来实现新的业务功能便可。

里氏代换原则

全部引用基类(父类)的地方必须能透明地使用其子类的对象。说白了就是:在软件中若是能使用其基类对象,那么必定能使用其子类对象。把基类都替换成它的子类,程序不会产生任何错误。但反过来则不成立,若是一个软件实体使用的是一个子类,那么它不必定能使用基类。

里氏代换原则是实现开闭原则的重要方式之一,在程序中尽可能使用基类类型来定义对象,而在运行时再肯定其子类类型,用子类对象来替代父类对象。

依赖倒转原则

高层模块不该该依赖低层模块,它们都应该依赖抽象。抽象不该该依赖于细节,细节应该依赖于抽象。即代码要依赖于抽象的类,而不依赖于具体的类,要针对接口编程,不要针对实现编程。

若是说开闭原则是面向对象设计的目标的话,那么依赖倒转原则就是面向对象设计的主要手段。下面介绍依赖倒转原则中常常提到的两个概念。

类之间的耦合:在面向对象系统中,两个类之间一般能够发生三种不一样的耦合关系(依赖关系)

1. 零耦合关系:两个类之间没有任何耦合关系
 2. 具体耦合关系:两个具体类之间存在一个类对另外一个具体类实例的直接引用
 3. 抽象耦合关系:发生在一个具体类和抽象类之间,也能够发生在两个抽象类之间。依赖倒转原则要求客户端依赖于抽象耦合。

依赖注入:简单来讲,依赖注入就是将一个类的对象传入另外一个类,注入时应该注入父类对象,而在程序运行时再经过子类对象来覆盖父类对象。依赖注入有三种方式

1. 构造注入:经过构造函数注入实例变量
 2. 设值注入:经过Setter方法注入实例变量
 3. 接口注入:经过接口方法注入实例变量

接口隔离原则

一旦一个接口太大,则须要将它分割成一些更小的接口,使用该接口的客户端仅需知道与之相关的方法便可。

这里的接口每每有两种不一样的含义:

一种是指一个类型所具备的方法的特征的集合,仅仅是逻辑上的概念,接口的划分将直接带来类型的划分。此时能够把接口理解成角色,一个接口只表明一个角色,每一个角色都有它特有的一个接口,此时这个原则叫作角色隔离原则。

另外一种是指接口仅仅提升客户端须要的行为,即所需的方法。接口应该尽可能细化,接口中的方法进来少,每一个接口只包含一个客户端所需的角色。

合成复用原则

尽可能使用组合对象,而不是继承来达到复用的目的。通俗来讲,合成复用原则就是指一个新的对象里经过关联关系(包括组合关系和聚合关系)来使用一些已有对象,使之成为新对象的一部分;新对象经过委派调用已有对象的方法达到复用已有功能的目的。

经过继承来实现复用很简单,子类能够覆盖父类方法,易于扩展。但会破坏系统的封装性,由于继承会将基类的实现细节暴露给子类,这种复用又称为“白箱复用”。

经过组合/聚合来复用是将一个类的对象做为另外一个类的对象的一部分。新对象能够调用已有对象的功能,这种复用又称为“黑箱复用”。

迪米特法则

指一个软件实体应尽量少的与其余实体发生相互做用。当一个模块修改时,就会尽可能少的影响其余模块,这是对软件实体之间通讯的限制,它要求软件实体之间通讯的宽度和深度。

在迪米特法则中,对于一个对象,其朋友包括如下几类:

当前对象自己(this)

以参数形式传入到当前对象方法中的对象

当前对象的成员对象

若是当前对象的成员对象是一个集合,那么集合中的元素也都是朋友

当前对象所建立的对象

任何对象若是知足上面的条件之一,就是当前对象的“朋友”,不然就是“陌生人”。

狭义的迪米特法则:若是两个类之间没必要彼此通讯,那么这两个类就不该当发生直接的相互做用。若是其中一个类须要调用另外一个类的某一个方法的话,能够经过第三者转发这个调用。狭义的迪米特法则能够下降类之间的耦合,但也会形成系统不一样模块之间通讯效率下降,使得系统的不一样模块之间不容易协调。

广义的迪米特法则:指对象之间的信息流量、流向以及信息的影响的控制,主要是对信息隐藏的控制。信息的隐藏可使各个子系统之间脱耦,每个模块不依赖于其余模块存在,所以每个模块均可以独立地在其余地方使用。

相关文章
相关标签/搜索