设计模式
Pattern - 模式(P)
建筑大师Christopher Alexander对模式的经典定义:每一种模式描述了一个不断重复发生的问题,以及该问题的解决方案的核心,即对重复发生的问题的描述和解决办法。
Design Pattern - 设计模式(DP)
代码设计经验的总结,使代码编制真正工程化,是软件工程的基石。设计模式默认指面向对象设计模式,但不局限于软件行业,本质是面向对象方法的实际运用,即对封装、继承、多态和关联的反复使用。
Oriented Object Design - 面向对象设计(OOD)
在系统设计的过程中,把系统分成相对独立但又互相联系的对象的组合。对象 = 属性 + 行为 + 关系,对象具有属性和行为,对象间通过消息进行交互协作。
参考:模式和原则;
GRASP:职责分配原则
设计模式是关于类和对象的一种高效灵活的使用方式,谈设计模式,须先谈类和对象,须先先谈GRASP。GoF等设计模式是针对特定问题提出的解决方法,GRASP是站在面向对象设计的更高角度看待面向对象软件的设计,针对如何把现实世界的业务功能抽象成类以及类的职责和相互间关系、如何决定一个系统有多少对象、每个对象都包括什么职责给出了最基本的指导原则。
General Responsibility Assignment Software Patterns,通用职责分配软件模式,由Craig Larman在《Applying UML and Patterns》一书中提出,核心思想是职责分配、用职责设计对象,解决面向对象设计的一些问题。GRASP包括9种模式,描述对象设计和职责分配的基本原则,是学习使用GoF等设计模式的基础的基础。
特点
- 职责的内聚分配,自己只干自己能干的事;
- 对象职责分配的基本原则,应用于分析和建模;
- GRASP所有模式的根本和核心概念:高内聚 + 低耦合,系统设计的终极目标;
GRASP九大模式
1. Information Expert (信息专家)
GRASP模式中解决类的职责分配问题的最基本的模式,是面向对象设计的最基本原则,对应于面向对象设计原则中的单一职责原则。
- 有能者为之,把职责分配给该职责所需信息的拥有者类;
- 封装性,对类的属性和操作的封装;
- 类的职责单一明确,信息的拥有者类同时也是信息的操作者类;
- 可能在某些情况中造成耦合;
2. Creator (创造者)
GRASP模式中解决类的实例的创建职责问题的模式,与各种工厂模式对应。
- 自生自灭,每个类负责创建自己包含/聚合的类的实例;
- 类B负责类A的实例的创建职责,类B是类A对象的创建者: B包含A、B聚合A、B记录A的实例、B拥有初始化A的数据并在创建类A的实例时将数据传递给类A、B频繁使用A;
- 降低耦合性、结构清晰,有利于类或组件的重用;
3. High Cohesion (高内聚)
GRASP模式中为降低类的复杂度、简化控制而提出的面向对象设计的原则性模式。
- 内聚是指单个类内部的功能聚集度,是评价一个元素的职责被关联和关注强弱的尺度;
- 各司其职,一个类只保留一组相关的属性和方法;
- 功能聚集,类的职责单一明确,模块化、结构清晰;
- 降低类的复杂程度,易维护;
4. Low Coupling (低耦合)
GRASP模式中为降低类间的关联度、适应可变性而提出的面向对象设计的原则性模式。
- 耦合是指多个类之间的关联程度,是评价一个系统中各元素间连接或依赖关系强弱的尺度;
- Don't Talk to Strangers,以降低类之间的耦合关系作为职责分配的原则;
- 类的独立性,易适应需求变化、减少类变更所带来的影响;
- 可重用,易维护;
高内聚低耦合要求把紧密关联的功能/职责聚集在同一个类中(减少类,防止功能扩散、减小耦合),把不相关的功能分散到不同的类(增加类,会增加可能耦合的机率)。
5. Controller (控制器)
GRASP模式中解决事件接收和处理职责问题的模式,与MVC模式中的C相对应。
- 运筹帷幄,控制器定义一组系统操作方法,是负责接收或者处理系统事件的非图形用户界面对象;
- 用一个专门的(高级)类来负责集中处理(协调和控制)所有的系统事件;
- 防止同类职责的分散,不同的子控制器类处理不同的事务;
- 可重用,高适应能力;
- 注意避免浮肿的控制器(Bloated Controllers);
6. Polymorphism (多态)
GRASP的扩展模式,通过多态操作把基于类型的可变行为的定义职责分配给行为发生的类,适应由于条件变化引发同一类型的不同行为,基于多态分配职责的设计与GoF多种设计模式相关。
- 多态性是指具有同一接口的不同对象对相同消息表现出不同行为,将不同的职责指定给不同的子类;
- 一物多用,用多态操作为行为变化的类型分配不同的职责,不同子类提供不同的实现方式;
- 避免代码重复、易维护,接口统一、易扩展;
- 利用多态性适应行为的可变性,变化适应能力强;
7. Pure Fabrication (纯虚构)
GRASP的扩展模式,把非问题领域中的某些难以分配的职责分配给人工定义的虚构的类或处理方便的“行为”类,是一种以功能为中心的对象或行为对象,与GoF多种设计模式相关。
- 抽象类/接口继承抽象类/接口,由一个纯虚构的类/接口来协调内聚和耦合;
- 避免破坏高内聚低耦合设计原则,一定程度上解决信息专家可能带来的低内聚高耦合设计;
- 高内聚低耦合,高可重用性;
Domain Class,问题领域里的类,与现实世界里的业务对象对应。各Domain类只处理问题领域以内的问题,问题领域以外的职责分配给第三方非Domain类。
8. Indirection (间接/中介)
GRASP模式中解决类的直接关联问题的模式,对应于面向对象设计原则中的迪米特法则。
- 把责任(协调多个组件/服务间的关联交互)分配给第三方类(中介),降低类间的耦合度;
- 原来的类之间间接关联、第三方类集中处理原来的类之间的关联功能;
- 高内聚低耦合,高可重用性;
9. Protected Variations (受保护变化)
GRASP的扩展模式,设计统一且稳定的接口应对可能发生的变化或不安定因素,在不修改已有代码的基础上扩展系统的功能,与面向对象设计原则中的开闭原则和依赖倒转原则相对应。
- 抽象化设计、定义抽象层,预先找出不稳定的变化点、用统一稳定的接口封装并承担职责;
- 面向接口编程,通过接口扩展新功能,无需修改原来的实现类;
- 具体功能在各子类中内聚实现,用户类只跟稳定接口通信;
- 高内聚低耦合,提高系统对变化的隔离和适应能力;
参考:
设计模式
GoF(Gang of Four),以不变应万变,GoF四人帮:Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides。比模式更重要的是原则,设计原则是设计模式的灵魂。面向对象设计原则和设计模式也是对系统进行合理重构的指导方针,相互依赖,相互补充。
特点
- 高内聚(模块内部的功能)、低耦合(模块之间的联系),对外低耦合、对内高内聚;
- 可维护、可扩展、可复用、灵活性好,可靠性高;
推荐书籍
- GOF -《设计模式:可复用面向对象软件的基础》
- Martin Flower -《企业架构模式》
- Robert C·Martin -《敏捷软件开发-原则、模式与实践》
- Larman -《UML和模式应用》
设计模式七大原则
1. 单一职责原则(Single Responsibility Principle,SRP):实现高内聚低耦合的指导方针
“就一个类而言,应该仅有一个引起它变化的原因。”
- 用于约束类、偏实现,一个类只负责并完全封装一项职责,降低类的复杂度;
- 类职责清晰明确、可读性好,易维护,降低变更引起的风险;
- 控制类的粒度大小,注意避免职责扩散;
2. 开闭原则(Open Close Principle,OCP):面向对象设计的核心和目标
“软件实体(类、模块、函数等)应该是可以扩展的,但是不可修改。” - Bertrand Meyer,1988
- 可变性封装原则,Principle of Encapsulation of Variation - EVP,预先封装可变因素,对扩展是开放的(Opend for Extension),对更改是封闭的(Closed for Modification),不允许修改的是抽象类/接口,允许扩展的是具体实现类;
- 关键是抽象化,用抽象构建框架、用实现扩展细节;;
- 创建抽象隔离以后可能发生的同类变化,增加新类以实现功能扩展而不更改原来的类;
3. 里氏替换原则(Liskov Substitution Principle,LSP):实现开闭原则的基础
“子类型必须能够透明地替换掉它们的基类型。”
- 继承中的“is-a”关系,确保继承被正确使用的手段;
- 子类可以扩展父类的功能、但不能改变父类原有功能,子类可以作为父类的代理工作、但父类不能作为子类的代理;
- 父类的方法可以在子类中重写,子类继承父类所有的非private的行为和属性。
- 尽量使用基类类型定义对象;
2008年图灵奖得主、美国第一位计算机科学女博士Barbara Liskov教授和卡内基·梅隆大学Jeannette Wing教授于1994年提出:如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1代换o2时,程序P的行为没有变化,那么类型S是类型T的子类型。
4.接口隔离原则(Interface Segregation Principle,ISP)
“不应该强迫客户依赖于它们不需要的接口/方法,为不同的客户端提供宽窄不同的接口。”
- 使用多个专门的单一职责接口,而不使用一个的总接口;
- 用于约束接口、偏抽象,专为依赖接口的类定制服务,建立最小的依赖关系;
- 控制接口的粒度大小;
5. 依赖倒转原则(Dependence Inversion Principle,DIP):面向对象设计的标志,
“抽象不应该依赖于细节,细节应该依赖于抽象。” - 对"抽象化"的最好规范,越抽象的才是越稳定的
- 高层模块不应该依赖于底层模块、两者都应该依赖于抽象(接口/抽象类);
- 针对接口/抽象编程、不要对实现编程,接口/抽象类制定规范和契约、具体的细节操作由实现类完成;;
- 接口注入,Interface Injection,通过接口传递依赖关系,即将具体类的对象通过依赖注入的方式注入到其他对象中;
- 要求客户端依赖于抽象耦合,以抽象方式耦合是依赖倒转原则的关键;
- 降低类间耦合、灵活性好,提高系统稳定性,降低修改程序造成的风险;
6. 最少知道原则(Least Knowledge Principle,LKP)
“如果两个类之间不必彼此直接通信,那么这两个类就不应当发生直接的相互作用,如果其中的一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。”
- 迪米特法则(Law of Demeter,LoD),在类的结构设计上,每一个类应当尽量降低成员的访问权限;
- 一个类对自己依赖的类知道的越少越好,一个实体对其他实体的引用越少越好;
- Don't talk to strangers and Talk only to your immediatefriends,只与直接的朋友通信,陌生类最好不要作为局部变量(非直接朋友)出现在类内部;
- 通过引入一个合理的第三者(中间类,Mediator)来降低现有对象间的耦合度,类之间松耦合、利于复用;
注:迪米特法则是目的,接口隔离法则是对迪米特法则的规范和约束,实现接口隔离法则达到迪米特法则的要求,用接口规范和约束类;
7. 合成复用原则(Composite/Aggregate Reuse Principle,C/ARP)
“要尽量使用对象组合/聚合,而不是继承关系达到复用的目的。”
- 继承是侵入性的、增加耦合度,多用组合、少用继承;
- 耦合度降低,系统更加灵活;
注:继承复用:实现简单、易扩展,破坏封装性、增加耦合度,静态实现、“白箱复用”,灵活性差; 合成复用:动态实现、“黑箱复用”,灵活性好;
参考:
23种经典设计模式
创建型模式
1. 工厂模式
1.1 简单工厂模式
1.2 工厂方法模式
1.3 抽象工厂模式
4. 单例模式
5. 原型模式
6. 建造者模式
结构型模式
1. 适配器模式
2. 桥接模式
3. 组合模式
4. 装饰模式
5. 外观模式
6. 享元模式
7. 代理模式
行为型模式
1. 职责链模式
2. 命令模式
3. 解释器模式
4. 迭代器模式
5. 中介者模式
6. 备忘录模式
7. 观察者模式
8. 状态模式
9. 策略模式
10. 模板方法模式
11. 访问者模式
参考:
参考:
- 设计模式 - 菜鸟教程;
- 我是怎样教媳妇OOD的:How I explained OOD to my wife; 我给媳妇解释设计模式:第一部分:How I explained Design Patterns to my wife: Part 1;
- 最全设计模式导学目录 - 完整版;