首页 > 代码库 > 设计模式概述

设计模式概述

面向对象设计原则

  • 单一职责原则 Single Responsibility Principle
    • 从软件变化的角度来看,就一个类而言,应该仅有一个让他发生变化的原因。
    • 正确抽象是实现SRP的关键
  • 开闭原则 Open-Closed Principle
    • 软件实体(类、模块、函数等等)应该是可以扩展的,但是不可修改的
    • 开闭原则是面向对象设计的核心,抽象是OCP的核心
    • 总有一些功能不能通过扩展来实现需要修改源代码,不要over-consider OCP
  • 里氏替换原则 Liskov Substitution Principle
    • 在任何父类出现的地方都可以用其子类替代。同一个继承体系中的对象应该有共同的行为特征。
    • 继承关系(IS-A)是基于对象的行为而非其概念,行为依赖于上下文和具体场景
    • LSP例子:java.util.Properties is a java.util.Hashtable
    • LSP是理论的而且严格的,有时候实际不能完全满足LSP是可以接受的
  • 依赖注入原则 Dependence Inversion Principle
    • 高层模块不应该依赖于低层模决,二者都应该依赖于抽象。
    • 进一步的,抽象不应该依赖于细节,细节应该依赖于抽象。
    • 针对接口编程,不要对实现编程
  • 接口分离原则 Interface Segregation Principle
    • 接口应该是原子的、高内聚扮演独立的角色或提供独立的角色。
    • ISP可以看做是SRP在接口中的描述。
  • 迪米特法则 Law Of Demeter
    • 一个对象应当对其他对象尽可能少的了解,只和直接依赖的对象通信降低各个对象之间的耦合,提高系统的可维护性
  • 组合/聚合复用原则 Composite/Aggregate Reuse Principle
    • 在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用已有功能的目的。
    • 组合是黑盒复用,包含对象的细节对于客户是不可见的。
    • 继承是白盒复用,强耦合,代码是静态的被复用。
    • 继承破坏了封装,父类的细节暴露给了子类。
    • 继承的实现是静态的,运行时候不能改变,缺乏灵活性。

设计模式

  • Creational Patterns 创建型(与对象创建相关)
    • Factory Method 工厂方法 (类模式)
    • Abstract Factory 抽象工厂
    • Singleton 单例
    • Builder 创建
    • Prototype 原型
  • Structural Patterns 结构型(处理类或对象的组合)
    • Adapter 适配器 (类或对象模式)
    • Decorator 装饰器
    • Composite 合成
    • Facade 外观
    • Flyweight 享元
    • Proxy 代理
    • Bridge 桥梁
  • Behavioral Patterns 行为型(对类或对象怎样交互和怎么分配职责进行描述)
    • Interpreter 解释器 (类模式)
    • Template Method 模板方法 (类模式)
    • Chain of Responsibility 责任链
    • Command 命令
    • Iterator 迭代器
    • Mediator 调停者
    • Memento 备忘录
    • Observer 观察者
    • State 状态
    • Strategy 策略
    • Visitor 访问者模式

类模式处理类和子类之间的关系,这些关系通过继承建立,是静态的,在编译时刻便确定下来了。
对象模式处理对象之间的关系,这些关系在运行时刻是可以变化的,更具动态性。
从某种意义上来说,几乎所有模式都使用了继承,所以这里类模式只指那些集中处理类之间关系的 模式,而大部分模式都属于对象模式。

  • 创建型类模式将对象的部分创建工作延迟到子类(工厂方法),而创建型对象模式则将它延迟到另一个对象中。
  • 结构型类模式使用继承机制来组合类(类适配器),而结构型对象模式则描述了对象的组装方式。
  • 行为模式使用继承描述算法和控制流(模板方法,解释器),而行为对象模式则描述一组对象怎样协作完成单个对象所无法完成的任务。

有些模式经常绑定一起使用,如Composite常和Iterator或Visitor一起使用;有些模式是可替换的Prototype常用来替换Abstract Factory;有些模式尽管使用意图不同,但产生的设计结果是很相似的,如Composite和Decorator的结构图相似的。

可以根据模式的“相关模式”部分所描述的它们怎样互相引用来组织设计模式,来进一步理解各种设计模式。
OOP Design Principles

设计模式解决设计问题

  1. 寻找合适的对象
    • 设计模式帮你确定并不明显的抽象和描述这些抽象的对象。描述过程或算法的对象现实中并不存在,但它们却是设计的关键部分
    • Strategy模式描述了怎样实现可互换的算法族。
    • State模式将实体的每一个状态描述为一个对象。
  2. 决定对象的粒度
    • Facade模式描述了怎样用对象表示完整的子系统,Flyweight模式描述了如何支持大量的最小粒度的对象。
    • 其他一些设计模式描述了将一个对象分解成许多小对象的特定方法。Abstract Factory和Builder产生那些专门负责生成其他对象的对象。
    • Visitor和Command生成的对象专门负责实现对其他对象或对象组的请求。
  3. 指定对象的接口
    • 设计模式通过确定接口的主要组成成分及经接口发送的数据类型,来帮助你定义接口。设计模式也许还会告诉你接口中不应包括哪些东西。
    • 设计模式也指定了接口之间的关系。Decorator和Proxy模式要求Decorator和Proxy对象的接口与被修饰的对象和受委托的对象一致。
    • Visitor模式中,Visitor接口必须反映出Visitor能访问的对象的所有类。
  4. 设计应支持变化。获得最大限度复用的关键在于对新需求和已有需求发生变化时的预见性,要求你的系统设计要能够相应地改进。一些导致重新设计的一般原因,以及解决这些问题的设计模式 如下:
    • 通过显式地指定一个类来创建对象。在创建对象时指定类名将使你受特定实现的约束而不是特定接口的约束。
      • 设计模式:Abstract Factory, Factory Method, Prototype
    • 对特殊操作的依赖。当你为请求指定一个特殊的操作时,完成该请求的方式就固定下来了。为避免把请求代码写死,你将可以在编译时刻或运行时刻很方便地改变响应请求的方法。
      • 设计模式:Chain of Responsibility, Command
    • 对硬件或软件平台的依赖。外部的操作系统接口和应用编程接口API在不同的软硬件平台上是不同的。
      • 设计模式:Abstract Factory, Bridge
    • 对对象表示或实现的依赖。知道对象怎样表示、保存、定位或实现的客户在对象发生变化时可能也需要变化。对客户隐藏这些信息能阻止连锁变化。
      • 设计模式:Abstract Factory, Bridge, Memento, Proxy
    • 算法依赖算法。在开发和复用时常常被扩展、优化和替代。依赖于某个特定算法的对象在算法发生变化时不得不变化。
      • 设计模式:Builder, Iterator, Strategy, Template Method, Visitor
    • 紧耦合。紧耦合的类很难独立地被复用,因为它们是互相依赖的。松散耦合提高了一个类本身被复用的可能性,并且系统更易于学习、移植、修改和扩展。设计模式使用抽象耦合和分层技术来提高系统的松散耦合性。
      • 设计模式:Abstract Factory, Command, Facade, Mediator, Observer, Chain of Responsibility
    • 通过生成子类来扩充功能。通常很难通过定义子类来定制对象。每一个新类都有固定的实现开销(初始化、终止处理等)。定义子类还需要对父类有深入的了解。一般的对象组合技术和具体的委托技术,是继承之外组合对象行为的另一种灵活方法。过多使用对象组合会使设计难于理解。许多设计模式产生的设计中,你可以定义一个子类,且将它的实例和已存在实例进行组合来引入定制的功能。
      • 设计模式:Bridge, Chain of Responsibility, Composite, Decorator, Observer, Strategy
    • 不能方便地对类进行修改。有时你不得不改变一个难以修改的类(可能没有源代码或者可能会改变其已存在子类)
      • 设计模式:Adapter, Decorator, Visitor

选择设计模式

  • 考虑设计模式是怎样解决设计问题的
  • 浏览模式的意图部分
  • 研究模式怎样互相关联
  • 研究目的相似的模式
  • 检查重新设计的原因
  • 考虑你的设计中哪些是可变的。考虑你想要什么变化却又不会引起重新设计。最主要的一点是封装变化的概念,这是许多设计模式的主题。下表列出了设计模式允许你独立变化的方面,你可以改变它们而又不会导致重新设计。
设计模式意图可变的方面
Abstract Factory提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。对产品对象家族
Builder将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。如何创建一个组合对象
Factory Method定义一个用于创建对象的接口,让子类决定将哪一个类实例化。Factory Method使一个类的实例化延迟到其子类。被实例化的子类
Prototype用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。被实例化的类
Singleton保证一个类仅有一个实例,并提供一个访问它的全局访问点。一个类的唯一实例
Adapter将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。对象的接口
Bridge将一个复杂对象的构建与它的表示分离,使它们都可以独立地变化。对象的实现
Composite将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得客户对单个对象和复合对象的使用具有一致性。对一个对象的结构和组成
Decorator动态地给一个对象添加一些额外的职责。就扩展功能而言,Decorator模式比生成子类方式更为灵活。对对象的职责,不生成子类
Facade为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。对一个子系统的接口
Flyweight运用共享技术有效地支持大量细粒度的对象。对象的存储开销
Proxy为其他对象提供一个代理以控制对这个对象的访问。如何访问一个对象;该对象的位置
Chain of Responsibility为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。满足一个请求的对象
Command将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。何时、怎样满足一个请求
Interpreter给定一个语言, 定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子。一个语言的文法及解释
Iterator提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。对如何遍历、访问一个聚合的各元素
Mediator用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。对象间怎样交互、和谁交互
Mementor在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的状态。对一个对象中哪些私有信息存放在该对象之外,以及在对什么时候进行存储
Observer定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。对多个对象依赖于另外一个对象,而这些对象又如何保持一致
State允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。对象的状态
Strategy定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法的变化可独立于使用它的客户。算法
Template Method定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。算法中的某些步骤
Visitor表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。某些可作用于一个(组)对象上的操作,但不修改这些对象的类

设计模式概述