不容错过的设计模式

深究设计模式,包含各种关于设计模式你不知道的细节。源码仓库位置

GoF(Gang of Four,四人帮)总结了23种常用的设计模式,这是基于具体场景提出的解决方案,具有一定的普遍性,可复用在不同场景中,然而实际场景远远不止23种,因此我们看到的大多数代码都不会是标准的类图,而是使用基于这23种设计模式衍生出的变种。

在学习过程中,我们会发现设计模式存在一些规律或者法则,以下是自己的一些理解:

  1. 不同模式之间只看类图的话存在很大的相似性:例如代理、适配器、装饰者核心实现都是通过组合对原来的类进行包装。门面模式和中介者模式都是通过组合多个对象,实现类与类之间的隔离。

    说到底类与类之间的关系简单来说无非就几种:继承(父子类)、实现(接口)、组合(成员变量)、依赖(方法参数)。而设计模式就是灵活运用和搭配这些关系,以实现软件的高内聚、低耦合。

    不同的是设计模式的出发点、使用场景、解决的问题存在差异。

  2. 设计模式不是孤立存在的,存在一定的关联,大部分时候系统开发中会同时用到多种设计模式。

  3. 大部分情况下使用组合都是面向接口或者抽象的,满足面向接口原则:例如代理、适配器等

    面向接口总结来讲无非就几大作用:

    1. 用于约束和强制子类实现,定义一个行为规范
    2. 利用多态提高扩展性,可随时替换具体实现
    3. 对外隐藏细节,外部只知道接口,不知道具体实现
  4. 设计模式不是死的,而是一种思想。大部分时候不会照搬设计模式的标准类图,而是使用它们的变种。例如

    1. 观察者模式:类图里面Subject对象需要维持一个观察者列表,实际使用中一般不需要用到列表。(如View事件监听)
    2. 策略模式:类图里面包含一个Context对象,实际使用中也可以不用,直接Client创建不同策略对象并调用。简单理解就是多态。
    3. 访问者模式:可以不定义抽象元素和具体元素,不重载接口方法,也可以不把元素放到列表中。只要满足对象结构接收访问者对象,并且在对象结构内部完成对子元素的遍历或访问,提供给访问者即可。目的是对外屏蔽访问规则和细节,例如内部可以遍历访问、递归访问、前序、后序访问等,访问者只需要接收到元素进行处理即可。
    4. 大部分模式砍掉类图中的接口之后,其实本质还是没有改变,明确接口的目的和意义。例如
      1. 代理是为了解决两个类之间无法直接通信的问题,并且代理类可以增加一些自己的行为(例如网络通信中的nginx代理,代理调用RPC服务等)。去掉接口之后还是能够达到这个目的,只不过缺少了对代理类的强制约束(要求代理类代理所有接口方法),并且没法使用Java的动态代理而已。
      2. 例如责任链模式,只要能够将多个对象串起来,并不一定要继承接口或抽象类
  5. 设计原则不止针对类,可以小到一个方法、接口,也可以大到包、模块层面。实际编码过程中要灵活运用。设计模式也一样,多从宏观和微观的角度思考和套用。

  6. 设计模式记忆方法:通过名称去理解,类比现实生活,思考各个模式的场景和出发点。如代理、中介者、适配器、观察者、门面、命令、迭代器、责任链、工厂等。类图只是其形,并不需要照搬,理解了名称之后才能理解其背后的思想,灵活变通。

    学习过程中可以多问自己为什么?如果不怎么做会产生什么问题?是否可以去掉某个部分?再尝试”自圆其说“,思考理由是什么。

  7. 学习设计模式可以从以下要素入手:模式名称、别名、动机、问题、解决方案、效果、结构、模式角色、模式扩展、相关模式、已有案例、生活中的实例等

  8. 框架>架构模式>设计模式>设计原则:存在一定的包含关系,如设计模式中会体现多种设计原则

设计模式分类大纲

创建型模式(5)

关注对象的创建,将对象的创建和使用分离,隐藏创建对象逻辑,避免直接new实例化对象。

  1. 工厂方法模式(Factory):定义一个用于创建产品的接口,由子类决定生产什么产品
  2. 抽象工厂模式(Abstract Factory):提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品
  3. 单例模式(Singleton):某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例。
  4. 建造者模式(Builder):将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象
  5. 原型模式(Prototype):将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。

结构型模式(8)

关注类或对象的组合,形成更大的结构

  1. 适配器模式(Adapter):将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
  2. 桥接模式(Bridge):将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
  3. 组合模式(Composite):将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性
  4. 装饰者模式(Decorator):动态的给对象增加一些职责或额外的功能。
  5. 外观模式(Facade):为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。
  6. 享元模式(Flyweight):运用共享技术来有效地支持大量细粒度对象的复用
  7. 代理模式(Proxy):为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。
  8. 过滤器模式(Filter、Criteria):也叫标准模式,使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。

行为型模式(12)

关注类或对象之间的通信,相互协作来完成功能。

  1. 策略模式(Strategy):定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户
  2. 责任链模式(Chain of Responsibility):把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。
  3. 命令模式(Command):将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开
  4. 迭代器模式(Iterator):提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
  5. 中介者模式(Mediator):定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解
  6. 观察者模式(Observer):多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。
  7. 状态模式(State):允许一个对象在其内部状态发生改变时改变其行为能力
  8. 模版方法模式(Template):定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
  9. 访问者模式(Visitor):在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问
  10. 解释器模式(Interpreter):提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。
  11. 备忘录模式(Memento):在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。
  12. 空对象模式(Null Object):使用空对象来替代null值,避免代码中判空。空对象中不做任何动作,在数据不可用的时候提供默认的行为。

其中过滤器和空对象模式不属于GoF的23种设计模式

结语

设计模式篇源码仓库位置

参考资料:C语言中文网-软件设计模式

results matching ""

    No results matching ""