- 基本理解
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。设计模式通过对软件开发过程中面临的一般性问题解决方案的总结,形成解决某类问题的软件流转控制框架范式,能够保证软件高效率、易维护、好扩展,代表了解决某类问题的最佳实践。同时设计模式也是软件设计的一种表达体系,使软件设计人员能够没有歧义的交流。
2.设计模式原则
原则是指经过长期经验总结所得出的合理化的现象,是行事所依据的准则。设计模式的原则也是我们软件设计的一些经验总结而形成的准则,业界有六大原则的说法也有七大原则的说法,本文采纳七大原则的说法,如下图所示:
设计模式的七大原则分别是:
1) 开放封闭原则 【目标:不修改既有代码,直接新增代码实现软件扩展】
2) 单一职责原则【实现途径:最大限度减少影响封装(模块)变更的因素】
3) 依赖倒转原则【实现途径:依赖的方向性,细节依赖于抽象】
4) 迪米特法则【实现途径:最大程度减少关联】
5) 接口隔离原则【实现途径:在接口设计中减少关联】
6) 合成/聚合复用原则【实现途径:多用动态关联,少用静态关联】
7) 里氏代换原则【实现途径:有限度的使用多态】
开放封闭原则:是一个总体的纲领性原则,是软件设计的终极目标,即是若要新增软件功能,不用修改既有代码,只需要额外增加代码即可实现(对扩展开放、对修改封闭)。其余六个原则是开放封闭原则的实现途径。
单一职责原则:对于一个类而言,应该仅有一个引起它变化的原因。类其实就是一个基本的封装单位,我们必须控制一个封装模块的职责,最大限度的减少可能引起变化的因素,降低封装模块变更的概率。
依赖倒转原则:高层模块不应该依赖低层模块,它们都应该依赖抽象;抽象不应该依赖于细节,细节应该依赖于抽象。简单来说,依赖倒转原则就是指:代码要依赖于抽象的类,而不要依赖于具体的类;要针对接口或抽象类编程,而不是针对具体类编程。
迪米特法则:又称为最少知识原则,简单地说,迪米特法则就是指一个软件实体应当尽可能少的与其他实体发生相互作用。这样,当一个模块修改时,就会尽量少的影响其他的模块,扩展会相对容易,这是对软件实体之间通信的限制,它要求限制软件实体之间通信的宽度和深度。
接口隔离原则:客户端不应该依赖那些它不需要的接口,一旦一个接口太大,则需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。一个接口应该承担一种相对独立的角色,不多不少,不干不该干的事,该干的事都要干。接口仅仅提供客户端需要的行为,即所需的方法,客户端不需要的行为则隐藏起来,应当为客户端提供尽可能小的单独的接口,而不要提供大的总接口。接口隔离原则是单一职责原则和迪米特法则在接口设计方面的具体体现。
合成复用原则:又称为组合/聚合复用原则,尽量使用对象组合,而不是继承来达到复用的目的。在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用其已有功能的目的。简言之:复用已有的设计和实现,要尽量使用组合/聚合关系,少用继承。因为继承复用是在代码中静态固化下来的,在运行时没有机会调整改变;而组合/聚合复用耦合度低,在运行时可以选择替换调用成员对象,具备动态调整的潜质,更具有灵活性。
里氏代换原则:所有引用基类(父类)的地方必须能透明地使用其子类的对象。里氏代换原则可以通俗表述为:在软件中如果能够使用基类对象,那么一定能够使用其子类对象。把基类都替换成它的子类,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类的话,那么它不一定能够使用基类。里氏代换原则实质上是对多态使用的一个限制,避免滥用多态造成设计上的缺陷。
3.设计模式分类
一个软件通常包括系统创建过程、系统运行过程和系统退出过程三个阶段,如下图所示:
设计模式通常分为创建型设计模式、结构型设计模式和行为型设计模式三个大类,实质上就是软件在不同过程中的典型解决方案总结,其中,创建型设计模式为系统的创建和退出过程提供了最佳实践,结合一些配置文件的使用,用户便可自定义系统的创建过程;行为型设计模式为系统的运行过程提供了最佳实践,使得处理过程能够最大限度的适应变更;结构型设计模式通过研究类/对象的组合方式,实现对类/对象的访问控制的最佳实践,对于软件的重构,代码优化有重要的参考意义。GOF设计模式的分类组成如下图所示:
4.设计模式要素一个设计模式主要包括<模式名称、应用场景、解决方案、模式运用、模式效果>五大要素,掌握了这五大要素,我们才能灵活运用设计模式。
模式名称是一个助记名,它用一两个词来描述模式的问题、解决方案和效果。命名一个新的模式增加了我们的设计词汇。设计模式允许我们在较高的抽象层次上进行设计。基于一个模式词汇表,我们自己以及同事之间就可以讨论模式并在编写文档时使用它们。模式名可以帮助我们思考,便于我们与其他人交流设计思想及设计结果。
应用场景描述应用模式解决什么问题,应该在何时使用模式。它解释了设计问题和问题存在的前因后果,它可能描述了特定的设计问题,如怎样用对象表示算法等;也可能描述了导致不灵活设计的类或对象结构;有时候,问题部分会包括使用模式必须满足的一系列先决条件。
解决方案描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式。因为模式就像一个模板,可应用于多种不同场合,所以解决方案并不描述一个特定而具体的设计或实现,而是提供设计问题的抽象描述和怎样用一个具有一般意义的元素组合(类或对象组合)来解决这个问题,面向对象的程序设计中解决方案通常就是一张类图。
模式运用描述客户端代码如何调用模式封装的代码,给出模式封装的代码的使用方式参考,划分清楚封装代码和客户端代码间的边界。
模式效果描述了模式应用的效果(优点缺点)及使用模式应权衡的问题。尽管我们描述设计决策时,并不总提到模式效果,但它们对于评价设计选择和理解使用模式的代价及好处具有重要意义。软件效果大多关注对时间和空间的衡量,它们也表述了语言和实现问题。因为复用是面向对象设计的要素之一,所以模式效果包括它对系统的灵活性、扩充性或可移植性的影响,显式地列出这些效果对理解和评价这些模式很有帮助。