设计模式

目录
    1 概述
    2 单例模式
    3 原型模式
    4 工厂模式
    5 抽象工厂模式
    6 建造者模式
    7 代理模式
    8 适配器模式
    9 桥接模式
    10 装饰模式
    11 外观模式
    12 享元模式
    13 组合模式
    14 模板方法模式
    15 策略模式
    16 命令模式
    17 责任链模式
    18 状态模式
    19 观察者模式
    20 中介者模式
    21 迭代器模式
    22 访问者模式
    23 备忘录模式
    24 解释器模式

参考资料
    · CSDN 单例模式(单例设计模式)详解
    · Javadop

1 概述

1.1 设计模式概念

    软件设计模式(Software Design Pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性。

1.2 23种设计模式分类

图 1-1 设计模式分类

1.2.1 根据目的来分

    根据模式是用来完成什么工作来划分,这种方式可分为创建型模式结构型模式行为型模式 3 种。

(1)创建型模式:用于描述“怎样创建对象”,它的主要特点是“将对象的创建与使用分离”。GoF 中提供了单例原型工厂方法抽象工厂建造者等 5 种创建型模式。

(2)结构型模式:用于描述如何将类或对象按某种布局组成更大的结构,GoF 中提供了代理、适配器、桥接、装饰、外观、享元、组合等 7 种结构型模式。

(3)行为型模式:用于描述类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,以及怎样分配职责。GoF 中提供了模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器等 11 种行为型模式。

1.2.2 根据作用范围来分

    根据模式是主要用于类上还是主要用于对象上来分,这种方式可分为类模式对象模式两种。

(1)类模式:用于处理类与子类之间的关系,这些关系通过继承来建立,是静态的,在编译时刻便确定下来了。GoF中的工厂方法、(类)适配器、模板方法、解释器属于该模式。

(2)对象模式:用于处理对象之间的关系,这些关系可以通过组合或聚合来实现,在运行时刻是可以变化的,更具动态性。GoF 中除了以上 4 种,其他的都是对象模式。

1.3 23种设计模式的功能

(1)单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。

(2)原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。

(3)工厂方法(Factory Method)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。

(4)抽象工厂(AbstractFactory)模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。

(5)建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。

(6)代理(Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。

(7)适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。

(8)桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

(9)装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。

(10)外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。

(11)享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用

(12)组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。

(13)模板方法(TemplateMethod)模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。

(14)策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。

(15)命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开

(16)职责链(Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。

(17)状态(State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。

(18)观察者(Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。

(19)中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。

(20)迭代器(Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。

(21)访问者(Visitor)模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。

(22)备忘录(Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。

(23)解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。

1.4 程序设计原则

(1)开闭原则:软件实体应当对扩展开放,对修改关闭(Software entities should be open for extension,but closed for modification)

(2)里氏替换原则:继承必须确保超类所拥有的性质在子类中仍然成立(Inheritance should ensure that any property proved about supertype objects also holds for subtype objects)

(3)依赖倒置原则:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程

(4)单一职责原则:一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分

(5)接口隔离原则(Interface Segregation Principle,ISP):要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用

(6)迪米特法则:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。

(7)合成复用原则:要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

2 单例模式

2.1 定义

    指一个类只有一个实例,且该类能自行创建这个实例的一种模式。

2.2 特点

(1)单例类只有一个实例对象;

(2)该单例对象必须由单例类自行创建;

(3)单例类对外提供一个访问该单例的全局访问点。

2.3 实现

    下面列出常见三种。

2.3.1 懒汉式单例

该模式的特点是类加载时没有生成单例,只有当第一次调用 getlnstance 方法时才去创建这个单例。代码如下:

public class LazySingleton{

    private static volatile LazySingleton instance=null;//保证 instance 在所有线程中同步

    private LazySingleton(){

    }//private 避免类在外部被实例化

    public static synchronized LazySingleton getInstance(){

        //getInstance 方法前加同步

        if(instance==null){

            instance = new LazySingleton();

        }

        return instance;

    }

}

注意:如果编写的是多线程程序,则不要删除上例代码中的关键字 volatile 和 synchronized,否则将存在线程非安全的问题。如果不删除这两个关键字就能保证线程安全,但是每次访问时都要同步,会影响性能,且消耗更多的资源,这是懒汉式单例的缺点。

2.3.2 饿汉式单例

该模式的特点是类一旦加载就创建一个单例,保证在调用 getInstance 方法之前单例已经存在了。

public class HungrySingleton{

    private static final HungrySingleton instance = new HungrySingleton();

    private HungrySingleton(){

    }

    public static HungrySingleton getInstance(){

        return instance;

    }

}

    饿汉式单例在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的,可以直接用于多线程而不会出现问题。

2.3.3 双重检验锁

图 2-1 双重检验锁

    对比懒汉式,首先看getInstance方法,我们在方法声明上去除了synchronized关键字,多线程进入方法内部,判断是否为null,如果为null,多个线程同时进入if块内,此时,我们是用Single4 Class对象同步一段方法。保证只有一个线程进入该方法。并且判断是否为null,如果为null,就进行初始化。我们想象一下,如果第一个线程进入进入同步块,发现该实例为null,于是进入if块实例化,第二个线程进入同步内则发现实例已经不是null,直接就返回 了,从而保证了并发安全。那么这个和懒汉式方式又什么区别呢?懒汉式方式的缺陷是:每个线程每次进入该方法都需要被同步,成本巨大。而双重检验锁方式呢?每个线程最多只有在第一次的时候才会进入同步块,也就是说,只要实例被初始化了,那么之后进入该方法的线程就不必进入同步块了。就解决并发下线程安全和性能的平衡。虽然第一次还是会被阻塞。

3 原型模式

3.1 定义

    用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。

3.2 实现

    Object 类中有一个 clone() 方法,它用于生成一个新的对象,当然,如果我们要调用这个方法,java 要求我们的类必须先实现 Cloneable 接口,此接口没有定义任何方法,但是不这么做的话,在 clone() 的时候,会抛出 CloneNotSupportedException 异常。

protected native Object clone() throws CloneNotSupportedException;

· 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

· 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

    Java 中的 Object 类提供了浅克隆的 clone() 方法,具体原型类只要实现 Cloneable 接口就可实现对象的浅克隆,这里的 Cloneable 接口就是抽象原型类。其代码如下:

//具体原型类

class Realizetype implements Cloneable{

    Realizetype(){

        System.out.println("具体原型创建成功!");

    }

    public Object clone() throws CloneNotSupportedException{

        System.out.println("具体原型复制成功!");

        return (Realizetype) super.clone();

    }

}

//原型模式的测试类

public class PrototypeTest{

    public static void main(String[]args) throws CloneNotSupportedException{

        Realizetype obj1=new Realizetype();

        Realizetype obj2=(Realizetype)obj1.clone();

        System.out.println("obj1==obj2?"+(obj1==obj2));

    }

}

4 工厂模式

4.1 定义

    定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。

    按实际业务场景划分,工厂模式有 3 种不同的实现方式,分别是简单工厂模式、工厂方法模式和抽象工厂模式。

4.2 简单工厂模式

(1)概念

    如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”。

    在简单工厂模式中创建实例的方法通常为静态(static)方法,因此简单工厂模式(Simple Factory Pattern)又叫作静态工厂方法模式(Static Factory Method Pattern)。

(2)实现

· 简单工厂(SimpleFactory):是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。

· 抽象产品(Product):是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。

· 具体产品(ConcreteProduct):是简单工厂模式的创建目标。

其结构图如下图所示。

图 4-1 简单工厂模式实现

4.3 工厂模式

(1)定义

    “工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。

(2)实现

· 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。

· 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。

· 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。

· 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同·具体工厂之间一一对应。

其结构图如图所示。

图 4-2 工厂模式实现

5 抽象工厂模式

5.1 定义

    是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构

5.2 实现

抽象工厂模式的主要角色如下:

· 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。

· 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。

· 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。

· 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

抽象工厂模式的结构图如图所示。

图 5-1 抽象工厂模式的结构图

6 建造者模式

6.1 定义

    指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。

6.2 实现

建造者(Builder)模式的主要角色如下:

· 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。

· 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。

· 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。

· 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。

其结构图如图所示。

图 6-1 建造者模式

    在实际代码中,通常可以构造成链式调用。

Food food =new FoodBuilder().a().b().c().build();
Food food = Food.builder().a().b().c().build();

7 代理模式

7.1 定义

    由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

7.2 实现

代理模式的主要角色:

· 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。

· 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。

· 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

其结构图如图所示

图 7-1 代理模式的结构图

8 适配器模式

8.1 定义

    将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类结构型模式对象结构型模式两种,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

8.2 实现

适配器模式(Adapter)包含以下主要角色。

· 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。

· 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。

· 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

(1)类适配器模式的结构图如图所示。

图 8-1 类适配器模式的结构图

(2)对象适配器模式的结构图如图所示。

图 8-2 对象适配器模式的结构图

9 桥接模式

9.1 定义

    将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

9.2 实现

· 抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用

· 扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。

· 实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。

· 具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。

其结构图如图所示。

图 9-1 桥接模式的结构图  

10 装饰模式

10.1 定义

    指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。

10.2 实现

装饰模式主要包含以下角色

· 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。

· 具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。

· 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具·体构件的功能。

· 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

装饰模式的结构图如图所示。

图 10-1 装饰模式的结构图  

11 Facade外观模式

11.1 定义

    外观(Facade)模式又叫作门面模式,是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。

11.2 实现

外观(Facade)模式包含以下主要角色。

· 外观(Facade)角色:为多个子系统对外提供一个共同的接口。

· 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。

· 客户(Client)角色:通过一个外观角色访问各个子系统的功能。

其结构图如图所示。

图 11-2 外观(Facade)模式的结构图  

12 享元模式

12.1 定义

    运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。

    享元模式的主要优点是:相同对象只要保存一份,这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。

12.2 实现

享元模式的主要角色有如下。

· 抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。

· 具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。

· 非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。

· 享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。

图中是享元模式的结构图,其中:

· UnsharedConcreteFlyweight 是非享元角色,里面包含了非共享的外部状态信息 info;

· Flyweight 是抽象享元角色,里面包含了享元方法 operation(UnsharedConcreteFlyweight state),非享元的外部状态以参数的形式通过该方法传入;

· ConcreteFlyweight 是具体享元角色,包含了关键字 key,它实现了抽象享元接口;

· FlyweightFactory 是享元工厂角色,它是关键字 key 来管理具体享元;

· 客户角色通过享元工厂获取具体享元,并访问具体享元的相关方法。

图 12-1 享元模式的结构图  

13 组合模式

13.1 定义

    有时又叫作整体-部分(Part-Whole)模式,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性。

13.2 实现

· 抽象构件(Component)角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)

· 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。

· 树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。

组合模式分为透明式的组合模式安全式的组合模式

(1) 透明方式

    在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。其结构图如图所示。

图 13-1 透明式的组合模式的结构图

(2) 安全方式

    在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。其结构图如图所示。

图 13-2 安全式的组合模式的结构图

14 模板方法模式

14.1 定义

    定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。

14.2 实现

(1)抽象类/抽象模板(Abstract Class)

    抽象模板类,负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下。

① 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。

② 基本方法:是整个算法中的一个步骤,包含以下几种类型。

· 抽象方法:在抽象类中声明,由具体子类实现。

· 具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。

· 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种

2)具体子类/具体实现(Concrete Class)

    具体实现类,实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。

模板方法模式的结构图如图 1 所示。

图 14-1 模板方法模式的结构图

15 策略模式

15.1 定义

    该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

15.2 实现

    策略模式的主要角色如下。

· 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。

· 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。

· 环境(Context)类:持有一个策略类的引用,最终给客户端调用。

其结构图如图所示。

图 15-1 策略模式的结构图  

16 命令模式

16.1 定义

    将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。

16.2 实现

· 抽象命令类(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法 execute()。

· 具体命令类(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。

· 实现者/接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。

· 调用者/请求者(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。

其结构图如图所示。

图 16-1 命令模式的结构图

17 责任链模式

17.1 定义

    为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

17.2 实现

职责链模式主要包含以下角色。

· 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。

· 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。

· 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

    责任链模式的本质是解耦请求与处理,让请求在处理链中能进行传递与被处理;理解责任链模式应当理解其模式,而不是其具体实现。责任链模式的独到之处是将其节点处理者组合成了链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动起来。

其结构图如图所示。客户端可按图中所示设置责任链。

图 17-1 责任链模式的结构图
图 17-2 责任链

18 状态模式

18.1 定义

    对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。

18.2 实现

· 环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。

· 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。

· 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。

其结构图如图所示。

图 18-1 状态模式的结构图

19 观察者模式

19.1 定义

    指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

19.2 实现

· 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。

· 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。

· 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。

· 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

观察者模式的结构图如图所示。

图 19-1 观察者模式的结构图  

20 中介者模式

20.1 定义

    定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。

20.2 实现

中介者模式包含以下主要角色。

· 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。

· 具体中介者(Concrete Mediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。

· 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。

· 具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。

中介者模式的结构图如图 1 所示。

图 20-1 中介者模式的结构图  

21 迭代器模式

21.1 定义

    提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。迭代器模式是一种对象行为型模式。

21.2 实现

· 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。

· 具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。

· 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。

· 具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

其结构图如图所示。

图 21-1 迭代器模式的结构图  

22 访问者模式

22.1 定义

    将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离,是行为类模式中最复杂的一种模式。

22.2 实现

· 抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。

· 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。

· 抽象元素(Element)角色:声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。

· 具体元素(ConcreteElement)角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。

· 对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。

其结构图如图所示。

图 22-1 访问者(Visitor)模式的结构图  

23 备忘录模式

23.1 定义

    在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。

23.2 实现

备忘录模式的主要角色如下。

· 发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。

· 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。

· 管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。

备忘录模式的结构图如图所示。

图 23-1 备忘录模式的结构图  

24 解释器模式

24.1 定义

    给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。

24.2 实现

· 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。

· 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。

· 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。

· 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。

· 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。

解释器模式的结构图如图所示。

图 24-2 解释器模式的结构图

你可能感兴趣的:(设计模式)