面向对象设计原则与设计模式大全

软件做得越久,越发觉得底层机制和原理的知识重要。

原文地址(侵删):http://blog.csdn.net/lovelion/article/details/17517213

如果再早几年看到这些文章,可能会觉得太教条了直接跳出,但最近读到这些总结已经十分全面的、系统化的知识时,如获至宝,重新整理了一下,以备自己不时复习。

面向对象设计原则

1. 单一职责原则 Single Responsibility Principle, SRP

一个类只负责一个功能领域中的相应职责。是实现高内聚、低耦合的指导方针,最简单但又最难运用的原则

2. 开闭原则 Open-Closed Principle, OCP

软件实体应对扩展开放,而对修改关闭。尽量在不修改原有代码的情况下进行扩展,抽象化是关键

3. 里氏代换原则 Liskov Substitution Principle, LSP

所有引用基类对象的地方能够透明地使用其子类。所以引用基类的地方必须能透明地使用其子类的对象

4. 依赖倒转原则 Dependence Inversion Principle, DIP

抽象不应用依赖于细节,细节应该依赖于抽象。使用接口和抽象类进行变量类型声明、参数类型声明、方法返回声明,以及数据类型转换等,而不要用具体类

5. 接口隔离原则 Interface Segregation Principle, ISP

使用多个专门的接口,而不使用单一的总接口。接口功能要单一,客户端只依赖它需要的接口

6. 合成利用原则 Composite Reuse Principle, CRP

尽量使用对象组合,而不是继承来达到复用的目的。新的对象通过关联关系来使用已有的对象,通过委派调用已有对象的方法达到复用功能的目的

7. 迪米特法则 Law of Demeter, LoD

一个实体应当尽可能少地与其他实体发生相互作用。降低系统的耦合度,使类与类之间保持松散的耦合关系

面向对象设计模式

6个创建型模式

1. 简单工厂模式 Simple Factory Pattern

定义一个工厂类,根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态方法,因此又被称为静态工厂方法模式。

2. 工厂方法模式 Factory Method Pattern

定义一个用于创建对象的接口,让子类决定将哪一个类实例化。又称为工厂模式 Factory Pattern、虚拟构造器模式 Virtual Constructor Pattern、多态工厂模式 Polymorphic Factory Pattern。

3. 抽象工厂模式 Abstract Factory Pattern

提供一个创建一系列相关或相互依赖对象的接口,无需指定具体的类,又叫Kit模式。它包含以下角色: - AbstractFactory 抽象工厂:它声明了一组用于创建一族产品的方法,每个方法对应一个产品 - ConcreteFactory 具体工厂:它实现了在抽象工厂中声明的创建方法,生成一组具体产品,这些产品构成一个产品族,每一个产品都位于某个产品等级结构中 - AbstractProduct 抽象产品:为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法 - ConcreteProduct 具体产品:实现抽象产品接口中声明的业务方法

4. 单例模式 Singleton Pattern

确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,提供全局访问方法。

饿汉式单例模式
class Singleton {
    private static final Singleton instance = new Singleton(); // 通过JDK本身实现单例
    public static Singleton getInstance() {
        return instance;
    }
}
懒汉式单例模式
class Singleton {
    private static Singleton instance = null;
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) { // 通过Synchronized保证原子性
                instance = new Singleton();
            }
        }
        return instance;
    }
}
更好的方法——静态内部类

通过 Initialization Demand Holder, IoDH 既能延迟加载,又可以保证线程安全,不影响系统性能。

class Singleton {
    private static class HolderClass {
        private final static Singleton instance = new Singleton();
    }
    public static Singleton getInstance() {
        return HolderClass.instance;
    }
}

5. 原型模式 Prototype Pattern

使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

class ConcretePrototype implements Prototype {
    private String attr;
    // 省略 attr 的 getter/setter 方法
    public Prototype clone() {
        Prototype prototype = new ConcretePrototype();
        prototype.setAttr(this.attr);
        return prototype;
    }
    // 使用 Java 语言提供的克隆机制
    public Prototype clone() {
        // 省略 try...catch
        return (Prototype)ConcretePrototype.clone();
    }
}
浅克隆

如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制给克隆对象,即,原型对象和克隆对象指向相同的内存地址;

深克隆

无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象。但需要序列化来实现,且实现Serializable接口。

...
public Prototype deepClone() throw IOException, ClassNotFoundException, OptionalDataException {
    // 将对象写入流中
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream();
    ostream.writeObject(this);
    // 将对象从流中读出,返回
    ByteArrayInputStream bis = new ByteArrayInputStream();
    ObjectInputStream ois = new ObjectInputStream();
    return (Prototype)ois.readObject();
}
...
原型管理器 Prototype Manager 的引用

将多个原型对象存储在一个集合中供客户端使用,它是一个专门负责克隆对象的工厂。

class PrototypeManager {
    private Hashtable ht = new Hashtable();
    private PrototypeManager() {
        ht.put("far", new FAR());
        ht.put("srs", new SRS());
    }
    // 饿汉式单例
    private static PrototypeManager pm = new PrototypeManager();
    public static PrototypeManager getPrototypeManager() {
        return pm;
    }
    public void addDemoObject(String key, DemoObject demo) {
        ht.put(key, demo);
    }
    public static DemoObject getDemoObject(String key) {
        return ((DemoObject)ht.get(key)).clone();
    }
}

6. 建造者模式 Builder Pattern

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。它包含以下角色:

  • Builder 抽象建造者:它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类是buildPathX(),它们用于创建复杂对象的各个部件;另一类是getResult(),它们用于返回复杂对象。Builder可以是抽象类也可以是接口。
  • ConcreteBuilder 具体建造者:它实现了Builder接口,实现各个部件的具体构造和装配,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
  • Product 产品:它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
  • Director 指挥者:又称导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其constrct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
class Director {
    private Builder builder;
    public Director(Builder builder) {
        this.builder = builder;
    }
    public void setBuilder(Builder builder) {
        this.builder = builder;
    }
    public Product construct() {
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
        return builder.getResult();
    }
}
// 客户端
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
Product product = director.construct();

7个结构型模式

7. 适配器模式 Adapter Pattern

将一个类的接口和另一个类的接口匹配,无须修改原来的适配者接口和抽象目标类接口,也叫包装器 Wrapper。它包含以下角色:

  • Target 目标抽象类:定义客户所需接口,可是以抽象类、接口、具体类;
  • Adapter 适配器类:可以调用另外一个接口,作为一个转换器,对Adapter和Target进行适配,是适配器模式的核心。在对象适配器中,它通过继承Target并关联一个Adapter对象使二者产生联系;
  • Adaptee 适配者类:被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,一般是具体类,包含了客户希望使用的业务方法,某些情况下可能没有适配者类的源码。
class Adapter extends Target {
    private Adaptee adaptee; // 维持一个对适配者对象的引用
    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }
    public void request() {
        adaptee.specificRequest(); // 转发调用
    }
}
双向适配器

如果在适配器中同时包含对目标类和适配者类的引用,适配者可以通过它调用目标类中的方法,目标类也可以通过它调用适配者类中的方法,那么该适配器就是一个双向适配器。

class Adapter implements Target.Adaptee {
    private Target target;
    private Adaptee adaptee;
    public Adapter(Target target) {
        this.target = target;
    }
    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }
    public void request() {
        adaptee.specificRequest();
    }
    public void specificRequest() {
        target.request();
    }
}
缺省适配器

当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用一个接口中的所有方法的情况,又称为单接口适配器模式。它包含以下三个角色:

  • ServiceInterface 适配者接口:通常在该接口中声明了大量的方法
  • AbstractServiceClass 缺省适配器类:核心,使用该空方法的形式实现了在ServiceInterface接口中声明的方法。通常将它定义为抽象类,因为对它进行实例化没有任何意义
  • ConcreteServiceClass 具体业务类:是缺省适配器类的子类,在没有引入适配器之前,它需要实现适配者接口,因此需要实现在适配者接口中定义的所有方法,而对于一些无须使用的方法也不得不提供空实现。在有了缺省适配器之后,可以直接继承该适配器类,根据需要有选择性地覆盖适配器类中定义的方法

8. 桥接模式 Bridge Pattern

将抽象部分与它的实现部分分离,使它们都可以独立地变化,又称为Handle of Body 柄体模式、Interface 接口模式,它包含以下几个角色:

  • Abstraction 抽象类:用于定义抽象类的接口,一般是抽象类而不是接口,其中定义了一个Implementor 实现类接口类型的对象并可以维护该对象,它与Implementor之间具有关联关系,可以包含抽象/具体业务方法
  • RefinedAbstraction 扩充抽象类:扩充由Abstraction定义的接口,通常情况下不再是抽象类而是具体类,实现了Abstraction声明的抽象业务方法,可以调用在Implementor中定义的业务方法
  • Implementor 实现类接口:定义实现类的接口,一般仅提供基本操作,子类负责实现。通过关联关系而非继承,Abstraction可以调用到这里的方法。
  • ConcreteImplmentor 具体实现类:实现Implementor接口,运行时将替换其父类对象,提供给抽象类具体的业务操作方法

9. 组合模式 Composite Pattern

组合多个对象形成树形结构以表示具有“整体-部分”关系的层次结构。对单个对象和组合对象的使用具有一致性,也叫“整体-部分 Part-Whole”模式,它包含以下几个角色:

  • Component 抽象构件:可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法
  • Leaf 叶子构件:表示叶子节点对象,没有子节点,实现在抽象构件中定义的行为
  • Composite 容器构件:表示容器节点对象,有子节点,子节点可以是Leaf也可以是Composite,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。

对于抽象构件角色典型的代码如下:

abstract class Component {
    public abstract void add(Component c); // 增加成员
    public abstract void remove(Component c); // 删除成员
    public abstract Component getChild(int i); // 获取成员
    public abstract void operation(); // 业务方法
}

对于叶子构件角色典型的代码如下:

class Leaf extends Component {
    ... // 需要实现抽象构件类中声明的所有方法
}

如果继承抽象构件的是容器构件,典型代码如下:

class Composite extends Component {
    private ArrayList<Component> list = new ArrayList<Component>();
    public void add(Component c) {
        list.add(c);
    }
    public void remove(Component c) {
        list.remove(c);
    }
    public Component getChild(int i) {
        return (Component)list.get(i);
    }
    public void operation() {
        for (Object obj : list) {
            ((Component)obj).operation();
        }
    }
}
透明组合模式

抽象构件Component中声明了所有用于管理成员对象的方法,好处是所有的构件类都有相同的接口,缺点是不够安全,叶子可能没有子节点操作方法,运行时会出错。

安全组合模式

抽象构件Component中没有声明任何用于管理成员对象的方法,好处是比较安全,缺点是不够透明,因为针对容器构件和叶子构件具有不同的方法,容器构件中又没有定义,因此客户端不能完全针对抽象编程,必须有区别对待它们。

10. 装饰模式 Decorator Pattern

装饰模式是一种用于替代继承的技术,它通过无须定义子类的方式来给对象动态增加职责,使用对象之间的关联关系取代类之间的继承,这样,既可以调用待装饰的原类的方法,又可以增加新方法,以扩充原类的功能,这比生成子类实现更为灵活。它包含以下几个角色:

  • Component 抽象构件:对具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法
  • ConcreteComponent 具体构件:它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中的声明方法,装饰器可以给它增加额外的方法
  • Decorator 抽象装饰类:也是抽象构件的子类,用于给具体构件增加职责,但具体职责在其子类中实现,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法
  • ConcreteDecorator 具体装饰类:是抽象装饰类的子类,负责向构件添加新的职责

核心在于抽象装饰类的设计,其典型代码如下:

class Decorator implements Component {
    private Component component;  // 维持一个对抽象构件对象的引用
    public Decorator(Component component) {  // 注入一个抽象构件类型的对象
        this.component = component;
    }
    public void operation() {
        component.operation();
    }
}

Decorator的子类即具有装饰类中将继承operation()方法并根据需要进行扩展,典型代码如下:

class ConcreteDecorator extends Decorator {
    public ConcreteDecorator(Component component) {
        super(component);
    }
    public void operation() {
        super.operation();  // 调用原来的业务方法
        addedBehavior();    // 调用新增的业务方法
    }
    public void addedBehavior() {
        ...
    }
}

11. 外观模式 Facade Pattern

为了避免和多个业务类同时交互,会设计一个类与之交互,客户只需要与该类交互,即为子系统中的一组接口提供一个统一的入口。它包含以下两个角色:

  • Facade 外观角色:它将所有从客户端发来的请求委派到相应的子系统去
  • SubSystem 子系统角色:软件系统中会有一个或多个子系统,每个都可以是一个类的集合,都可以被客户端或外观角色调用

例如,子系统如下定义:

class SubSystemA {
    public void MethodA() {...}
}
class SubSystemB {
    public void MethodB() {...}
}
class SubSystemC {
    public void MethodC() {...}
}

外观角色定义:

class Facade {
    private SubSystemA obj1 = new SubSystemA();
    private SubSystemB obj2 = new SubSystemB();
    private SubSystemC obj3 = new SubSystemC();
    public void Method() {
        obj1.MethodA();
        obj2.MethodB();
        obj3.MethodC();
    }
}

客户端调用时:

public class Program {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.Method();
    }
}
抽象外观类

引入一个抽象外观类,客户端针对抽象外观类编程,运行时再确定具体外观类,如通过配置文件。

12. 享元模式 Flyweight Pattern

通过共享技术实现相同或相似对象的重用,其中存储共享实例对象的地方称为享元池,又叫轻量级模式。它包含以下几个角色:

  • Flyweight 抽象享元类:一个接口或抽象类,其中声明了公共方法
  • ConcreteFlyweight 具体享元类:实现了抽象享元类,其实例称为享元对象,通常结合单例模式
  • UnsharedConcreteFlyweight 非共享具体享元类:不能被共享的子类
  • FlyweightFactory 享元工厂类:创建并管理享元对象,将各种类型的具体享元对象存储在一个享元池中,一般设计为一个键值对的集合,结合工厂模式进行设计

典型的享元工厂类代码如下:

class FlyweightFactory {
    private HashMap flyweight = new HashMap();
    public Flyweight getFlyweight(String key) {
        if (flyweight.containsKey(key)) {
            return (Flyweight)flyweight.get(key);
        } else {
            Flyweight fw = new ConcreteFlyweight();
            flyweight.put(key, fw);
            return fw;
        }
    }
}

享元类代码如下:

class Flyweight {
    private String intrinsicState;
    // 内部状态intrinsicState作为成员变量,同一个享元对象其内部状态是一致的
    public Flyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }
    // 外部状态extrinsicState在使用时由外部设置,不保存在享元对象中
    public void operation(String extrinsicState) {
        ...
    }
}
单纯享元模式

所有具体享元类都是可以共享的

复合享元模式

将一些单纯享元对象使用组合模式加以组合,可以形成复合享元对象,这样它就不能共享

13. 代理模式 Proxy Pattern

给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问,它包含以下几个角色:

  • Subject 抽象主题角色:它声明了真实主题和代理主题的共同接口,这样任何使用真实主题的地方都可以使用代理主题
  • Proxy 代理主题角色:包含了对真实主题的引用,从而可以操作真实主题对象
  • RealSubject 真实主题角色:定义了代理角色所代表的真实对象,实现了真实的业务操作

典型的抽象主题类代码:

abstract class Subject {
    public abstract void Request();
}

真实主题类代码:

class RealSubject : Subject {
    public override void Request() {...}
}

代理类实现代码:

class Proxy : Subject {
    private RealSubject realSubject = new RealSubject();
    public void PreRequest() {...}
    public void PostRequest() {...}
    public override void Request() {
        PreRequest();
        realSubject.Request();
        postRequest();
    }
}

实际开发中常用的几种代理模式:

  • Remote Proxy 远程代理:为位于不同地址的对象提供一个本地的代理对象,又称为大使
  • Virtual Proxy 虚拟代理:如果需要创建一个资源消耗大的对象,先创建一个资源消耗小的来表示
  • Protect Proxy 保护代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限
  • Cache Proxy 缓冲代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端共享
  • Smart Reference Proxy 智能引用代理:当一个对象被引用时,提供一些额外的操作,如记录调用次数

11个行为型模式

14. 职责链模式 Chain of Responsibility Pattern

避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止,它包含以下几个角色:

  • Handler 抽象处理者:定义一个抽象类处理请求接口
  • ConcreteHandler 具体处理者:抽象处理者的子类,可以处理用户请求,在请求处理之前需要进行判断,看是否有权限,否则转发给后继者
abstract class Handler {
    protected Handler successor;
    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }
    public abstract void handleRequest(String request);
}
class ConcreteHandler extends Handler {
    public void handleRequest(String request) {
        if (满足条件) {
            // 处理请求
        } else {
            this.successor.handleRequest(request); // 转发请求
        }
    }
}

职责链模式并不创建职责链,它必须由系统的其他部分来完成,一般是使用该职责链的客户端。

纯的职责链模式

要么承担全部职责,要么将职责推给下家,不允许出现一个具体处理者在承担了一部分或全部职责后又将职责向下传递的情况,即,要求一个请求必须被一个处理者对象所接收。

不纯的职责链模式

允许某个请求被一个具体处理者部分处理后再向上传递,或者一个具体处理者处理完再向下传递,而且一个请示可以最终不被任何处理者对象接收。

15. 命令模式 Command Pattern

可以将请求发送者和接收者完全解耦,他们之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成,它包含以下几个角色:

  • Command 命令类:一般是一个抽象类或接口,其中声明了用于执行的execute()等方法
  • ConcreteCommand 具体命令类:是抽象命令类的子类,实现抽象类中声明的方法,在实现execute()方法时,将调用接收者对象的相关操作(Action)
  • Invoker 调用者:即请求发送者,通过命令对象来执行请求。不需要在设计时指定接收者,运行时再注入具体命令对象,并调用其中的execute()方法
  • Receiver 接收者:执行与请求相关的操作,实现对请求的业务处理

本质是对请求进行封装,一个请求对应一个命令,将发出命令的责任和执行命令的责任分开。

abstract class Command {
    public abstract void execute();
}
class Invoker {
    private Command command;
    public Invoker(Command command) {
        this.command = command;
    }
    public void setCommand(Command command) {
        this.command = command;
    }
    public void call() {
        command.execute();
    }
}
class ConcreteCommand extends Command {
    private Receiver receiver;
    public void execute() {
        receiver.action();
    }
}
class Receiver {
    public void action() {
        // TODO: 具体操作
    }
}
命令队列的实现

将多个请求排队,当一个请求发送者发送一个请求时,将不止一个请求接收者产品响应,这些请求接收者将逐个执行业务方法,完成对请求的处理。

撤销操作的实现

通过调用命令对象的execute()方法实现对请求的处理,如果需要撤销,可以通过在命令类中增加一个逆向操作来实现,除此之外还可以通过保存对象的历史状态来实现(备忘录模式)。

16. 解释器模式 Interpreter Pattern

描述了如何为简单的语言定义一个方法,以表示和解释这个句子,它包含以下几个角色:

  • AbstractExpression 抽象表达式:声明了抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共父类
  • TerminalExpression 终结表达式:实现了与文法中的终结符相关联的解释操作,句子中的每一个终结符都是该类的一个实例
  • NonterminalExpression 非终结表达式:实现了文法中非终结符的解释操作,由于在非终结符表达式中可以包含终结符表达式,因此其解释操作一般通过递归方式完成
  • Context 环境类:每一种终结符和非终结符都有一个具体类与之对应
abstract class AbstractExpression {
    public abstract void interpret(Context ctx);
}
class TerminalExpression extends AbstractExpression {
    public void interpret(Context ctx) {
        // 终结符表达式的解释操作
    }
}
class NonterminalExpression extends AbstractExpression {
    private AbstractExpression left;
    private AbstractExpression right;
    public NonterminalExpression(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }
    public void interpret(Context ctx) {
        // 递归调用每一个组成部分的interpret()方法
    }
}
class Context {
    private HashMap map = new HashMap();
    public void assign(String key, String value) {
        // 往环境类中设值
    }
    public String lookup(String key) {
        // 获取存储在环境类中的值
    }
}

17. 迭代器模式 Iterator Pattern

将聚合类中负责遍历数据的方法提取出来,封装在专门的类中,实现数据存储和数据遍历的分离,无须暴露聚合类的内部属性即可对其进行操作,其别名为游标,它包含以下几个角色:

  • Interator 抽象迭代器:定义了访问和遍历元素的接口,声明了用于遍历数据元素的方法,如:
    • 用于获取第一个元素的first()方法
    • 用于访问下一个元素的next()方法
    • 用于判断是否还有下一个元素的hasNext()方法
    • 用于获取当前元素的currentItem()方法等
  • ConcreteInterator 具体迭代器:实现了抽象迭代器接口,完成对聚合对象的遍历,同时在具体迭代器中通过游标来记录在聚合对象中所处的当前位置,在具体实现时,游标通常是一个表示位置的非负整数
  • Aggregate 抽象聚合类:用于存储和管理元素对象,声明一个createIterator()方法用于创建一个迭代器对象,充当抽象迭代器工厂角色
  • ConcreteAggregate 具体聚合类:实现了在抽象聚合类中声明的createIterator()方法,该方法返回一个与该具体聚合类对应的具体迭代器 ConcreteIterator 实例
interface Iterator {
    public void first();          // 将游标指向第一个元素
    public void next();           // 将游标指向下一个元素
    public boolean hasNext();     // 判断是否存在下一个元素
    public Object currentItem();  // 将游标指向当前元素
}
class ConcreteIterator implements Iterator {
    private ConcreteAggregate objects; // 维持一个对具体聚合类对象的引用,以便于访问存储在聚合对象中的数据
    private int cursor;  // 定义一个游标,用于记录当前访问位置
    public ConcreteIterator(ConcreteAggregate objects) {
        this.objects = objects;
    }
    public void first() { ... }
    public void next() { ... }
    public boolean hasNext() { ... }
    public Object currentItem() { ... }
}
interface Aggregate {
    Iterator createIterator();
}
class ConcreteAggregate implements Aggregate {
    public Iterator createIterator() {
        return new ConcreteIterator(this);
    }
}

18. 中介者模式 Mediator Pattern

用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互,是“迪米特法则”的一个典型应用,它包含以下几个角色:

  • Mediator 抽象中介者:定义一个接口,用于与各同事对象之间进行通信
  • ConcreteMediator 具体中介者:是抽象中介者的子类,通过协调各个同事对象来实现协作行为,它维持了对各个同事对象的引用
  • Colleague 抽象同事类:定义各个同事类公有的方法,并声明了一些抽象方法来供子类实现,它维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信
  • ConcreteColleague 具体同事类:是抽象同事类的子类,每一个同事对象在需要和其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信,在具体同事类中实现了在抽象同事类中声明的抽象方法

中介者模式将一个网状的系统结构变成一个以中介者对象为中心的星形结构。抽象者模式的核心在于中介者类的引用,中介者类承担了两方面的职责:

  • 中转作用(结构性):通过中介者提供的中转作用,各个同事对象就不再需要显式引用其他同事,当需要和其他同事通信时,可通过中介者来实现间接调用
  • 协调作用(行为性):中介者可以进一步对同事之间的关系进行封装,同事可以一致的和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑,对同事的请求进行进一步处理,奖同事成员之间的关系行为进行分离和封装
abstract class Mediator {
    protected ArrayList<Colleague> colleagues;  // 用于存储同事对象
    // 注册方法,用于增加同事对象
    public void register (Colleague colleague) {
        colleagues.add(colleague);
    }
    public abstract void operation();  // 声明抽象的业务方法
}
class ConcreteMediator extends Mediator {
    public void operation() {
        ...
        ((Colleague)(colleagues.get(0))).method1();  // 通过中介者调用同事类方法
        ...
    }
}
abstract class Colleague {
    protected Mediator mediator;  // 维持一个抽象中介者的引用
    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }
    public abstract void method1();  // 声明自身方法,处理自己的行为
    // 定义依赖方法,与中介者进行通信
    public void method2() { mediator.operation(); }
}
class ConcreteColleague extends Colleague {
    public ConcreteColleague(Mediator mediator) {
        super(mediator);
    }
    public void method1() { ... }  // 实现自身方法
}

19. 备忘录模式 Memento Pattern

备忘录模式提供了一种状态恢复的实现机制,在不破坏封装的前提下,捕获一个对象的内部状态,并在一个对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态,它包含以下几个角色:

  • Originator 原发器:是一个普通类,可以创建一个备忘录,并存储它的当前内部状态,也可以使用备忘录来恢复其内部状态,一般将需要保存的内部状态的类设计为原发器
  • Memento 备忘录:存储原发器的内部状态,根据原发器来决定保存哪些内部状态。一般可以参考原发器的设计,根据实现需要确定备忘录类中的属性,但需要注意的是,除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用
  • Caretaker 负责人:又叫管理者,它负责保存备忘录,但是不能对备忘录的内容进行操作或检查
public class Originator {
    private String state;
    public Originator() {}
    public Memento createMemento() {
        return new Memento(this);
    }
    public void restoreMemento(Memento memento) {
        state = memento.state;
    }
    public void setState(String state) { this.state = state; }
    public String getState() { return this.sate; }
}
class Memento {
    private String state;
    public Memento(Originator originator) {
        state = originator.getState();
    }
    public void setState(String state) { this.state = state; }
    public String getState() { return this.state; }
}
public class Caretaker {
    private Memento memento;
    public Memento getMemento() { return this.memento; }
    public void setMemento(Memento memento) { this.memento = memento; }
}

20. 观察者模式 Observer Pattern

用于建立一种对象与对象之间的依赖关系,一个对象发生改变时,其依赖对象皆得到通知并被自动更新。又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式、从属者(Dependents)模式,它包含如下几个角色:

  • Subject 目标:又称为主题,即被观察的对象,可以是接口或抽象类。定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它又定义了通知方法notify()
  • ConcreteSubject 具体目标:通常包含经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知,同时实现了在目标类中定义的抽象业务逻辑方法,如无须扩展目标类,可省略
  • Observer 观察者:观察者将对观察目标的改变作出反应,一般定义为接口,声明了更新数据的方法update(),又称为抽象观察者
  • ConcreteObserver 具体观察者:维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法。通常在实现时,可以调用具体目标类的attach()方法将自己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除
abstract class Subject {
    // 定义一个观察者集合用于存储所有观察者对象
    protected ArrayList<Observer> observers = new ArrayList<Observer>();
    // 注册方法,用于向观察者集合中增加一个观察者
    public void attach(Observer observer) {
        observers.add(observer);
    }
    // 注销方法,用于向观察者集合中删除一个观察者
    public void detach(Observer observer) {
        observers.remove(observer);
    }
    public abstract void notify();  // 声明抽象通知方法
}
class ConcreteSubject extends Subject {
    // 实现通知方法
    public void notify() {
        // 遍历观察者集合,调用每一个观察者的响应方法
        for(Object obj : observers) {
            ((Observer)obj).update();
        }
    }
}
interface Observer {
    public void update();  // 声明响应方法
}
class ConcreteObserver implements Observer {
    // 实现响应方法
    public void update() {
        // 具体响应代码
    }
}

21. 状态模式 State Pattern

用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类,其别名为状态对象(Objects States),它包含如下几个角色:

  • Context 环境类:是拥有多种状态的对象
  • State 抽象状态类:用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各个不同状态对应的方法,而在其子类中实现这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中
  • ConcreteState 具体状态类:是抽象状态类的子类,每一个子类实现一个与环境尖的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同
abstract class State {
    // 声明抽象业务方法,不同的具体状态类可以有不同的实现
    public abstract void handle();
}
class ConcreteState extends State {
    public void handle() {
        // 方法具体实现代码
    }
}
class Context {
    private State state;  // 维持一个对抽象状态对象的引用
    private int value;  // 其他属性值,该属性值的变化可能会导致对象状态发生变化
    public void setState(State state) { this.state = state; }
    public void request() {
        ...  // 可能有其他代码
        state.handle();  // 调用状态对象的业务方法
        ...  // 可能有其他代码
    }
}

一个对象的状态之间可以相互转换,通常有两种方式:

统一由环境类来负责状态之间的转换
public void changeState() {
    if (value == 0) {
        this.setState(new ConcreteStateA());
    } else if (value == 1) {
        this.setState(new ConcreteStateB());
    }
}
由具体状态类来负责状态之间的转换
public void chageState(Context context) {
    int state = context.getValue();
    if (state == 1) {
        context.setState(new ConcreteStateA());
    } else if (state == 2) {
        context.setState(new ConcreteStateB());
    }
}

有些情况下多个环境对象可能会共享同一个状态,可以将这些状态对象定义为环境类的静态成员对象。

22. 策略模式 Strategy Pattern

定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法,这样的类叫策略。它的主要目的是将算法的定义与使用分开,也就是将算法的行为与环境分开,它包含如下几个角色:

  • Context 环境类:是使用算法的角色,在解决问题时可以采用多种策略
  • Strategy 抽象策略类:为所支持的算法声明了抽象方法,是所有策略类的父类,可以是抽象类、具体类或接口
  • ConcreteStrategy 具体策略类:实现了在抽象策略类中声明的算法,运行时具体策略类将覆盖在环境类中定义的抽象策略类
abstract class Strategy {
    public abstract void algorithm();  // 声明抽象算法
}
class ConcreteStrategy extends Strategy {
    public void algorithm() { ... }  // 具体算法实现
}
class Context {
    private Strategy strategy;  // 维持一个对抽象策略类的引用
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    public void algorithm() {
        strategy.algorithm();
    }
}

客户端调用时:

...
Context context = new Context();
Strategy strategy = new ConcreteStrategy(); // 也可以运行时指定
context.setStrategy(strategy);
context.algorithm();
...

23. 模板方法模式 Template Method Pattern

模板方法模式是基于继承的代码复用技术,它定义了一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤,它包含如下两个角色:

  • AbstractClass 抽象类:定义了一系列基本操作(Primitive Operations),这些基本操作可以是具体的也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中重定义或实现它们。同时在抽象类中实现了一个模板方法,用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的方法,也可以调用在抽象类的子类中实现的方法,还可以调用其他对象的方法
  • ConcreteClass 具体子类:是抽象类的子类,用于实现在父类中声明的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作
模式的实现
  • 模板方法:是定义在抽象类中的、把基本操作方法组合在一起形成一个总算法或一个总行为的方法,只能是抽象类
  • 基本方法:
    • 抽象方法:由抽象类声明,由其具体子类实现
    • 具体方法:由抽象类或具体类声明并实现
    • 钩子方法:由抽象类或具体类声明并实现,而其子类可能会加以扩展,通常在父类中给出空实现,子类实现之
    • 第一类钩子方法可以与一些具体步骤挂钩
    • 第二类钩子方法就是实现体为空的具体方法
public void TemplateMethod() {
    method_1();
    if (isOK()) {  // 通过钩子方法确定某步骤是否执行
        method_2();
    }
}
public boolean isOK() { return true; }
abstract class AbstractClass {
    // 模板方法
    public void TemplateMethod() {
        method_1();
        method_2();
        method_3();
    }
    public void method_1() { ... }
    public abstract void method_2() { ... }
    public virtual void method_3() { ... }
}

24. 访问者模式 Visitor Pattern

访问者模式包含访问者和被访问者两个主要组成部分,这些被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。访问者模式使得用户可以在不修改现有系统的情况下扩展系统的功能,为不同类型的元素增加新的操作,它包含如下几个角色:

  • Visitor 抽象访问者:为对象结构中每一个具体元素类ConcreteElement声明一个访问操作,从这个操作的名称或参数类型可以清楚知道需要访问的具体元素的类型
  • ConcreteVisitor 具体访问者:实现了每个由抽象访问者声明的操作,每一个操作用于访问对象结构中一种类型的元素
  • Element 抽象元素:一般是抽象类或接口,它定义了一个accept()方法,通常以一个抽象访问者作为参数
  • ConcreteElement 具体元素:实现accept()方法,调用访问者的访问方法以便完成对一个元素的操作
  • ObjectStructure 对象结构:是一个元素的集合,它用于存放元素对象,并且提供遍历其内部元素的方法
abstract class Visitor {
    public abstract void visit(ConcreteElementA elementA);
    public abstract void visit(ConcreteElementB elementB);
    public void visit(ConcreteElementC elementC) {
        ... // 元素 ElementC 操作代码
    }
}
class ConcreteVisitor extends Visitor {
    public void visit(ConcreteElementA elementA) {
        ... // 元素 elementA 操作代码
    }
    public void visit(ConcreteElementB elementB) {
        ... // 元素 elementB 操作代码
    }
}
interface Element {
    public void accept(Visitor visitor);
}
class ConcreteElementA implements Element {
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public void operationA() {
        ... // 业务方法
    }
}