23种设计模式总结(读书笔记版)

107 阅读11分钟

创建型模式

1. 单例模式(Singleton Pattern)—— 确保对象的唯一性

确保一个类只有一个实例,并提供全局访问单点。

juejin.cn/post/698520…

2. 工厂方法模式(Factory Method Pattern)—— 多态工厂的实现

定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

juejin.cn/post/698941…

3. 抽象工厂模式(Abstract Factory Pattern)—— 产品族的创建

提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

juejin.cn/post/698941…

4. 原型模式(Prototype Pattern)—— 对象的克隆

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象

juejin.cn/post/699074…

5. 建造者模式(Builder pattern)—— 复杂对象的组装与创建

建造者(Builder pattern)模式的定义:将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示

juejin.cn/post/699186…

结构型模式

6. 适配器模式(Adapter Pattern)—— 不兼容结构的协调

将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

// 适配器实现目标的接口
public interface Target{
    public void request();
}

// 被适配者
public interface Adaptee{
    public void specificRequest();
}

// 适配者
public class Adapter implements Target{
    private Adaptee adaptee;

    public Invoker(Adaptee adaptee){
        this.adaptee = adaptee;
    }
    
    public void request(){
        // 所有的请求都委托给被适配者。
        adaptee.specificRequest();
    }
}

public class Client{
    public static void main(String[] args){
        Adaptee adaptee = new Adaptee();
        Target target = new Adapter(adaptee);
        target.request();
    }
}

适配器可分为对象适配器和类适配器。上面的即为对象适配器。类适配器通过多继承的方式实现(适配器继承被适配者,并实现目标类方法)

7. 桥接模式(Bridge Pattern)—— 处理多维度变化

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

juejin.cn/post/699739…

8. 组合模式(Composite Pattern)—— 树形结构的处理

允许你将对象组成树形结构来表现“整体/部分”的层次结构。组合能让客户以一致的方式处理个别对象和对象组合。

场景:一个菜单里面可包括具体的菜单项和子菜单。可参考如下实现:

// 菜单组件(即可表示菜单项,又可表示子菜单)
public abstract class MenuComponent{
    // 具体菜单项的相关接口
    public double getPrice(){
        throw new Execption("不支持的操作");
    }

    // 子菜单项的相关接口
    public void add(MenuComponent menuComponent){
        throw new Execption("不支持的操作");
    }
}

// 菜单项
public class MenuItem extends MenuComponent{
    public double getPrcie(){
        return 5.2;
    }
}

public class Menu extends MenuComponent{
    private List<MenuComponent> content = new ArrayList();

    public void add(MenuComponent menuComponent){
        content.add(menuComponent);
    }
}

public class Client{
 
    psvm(args){
        // 根菜单
        MenuComponent root = new Menu();
        // 子菜单
        MenuComponent subMenu = new Menu();
        MenuComponent menuItem = new MenuItem();
        root.add(subMenu);
        root.add(menuItem);
    }
}

9. 装饰者模式(Decorator Pattern)—— 扩展系统功能

动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

JDK中的应用:

InputStream为抽象类。FileInputStream为具体实现类,实现read等方法。BufferedInputStream为装饰对象,它有一个InputStream对象,并“装饰”了这个InputStream对象功能,即扩展了其功能。(通过增加Buff的形式实现)。

伪代码

public abstract class InputStream{
    public abstract int read();

    public int read(byte[] data, int off, int len){
        
    }
}

public class FileInputStream() extend InputStream{
    public int read(){
        
    }
    public int read(byte[] data, int off, int len){
        
    }
}

public class BufferedInputStream() extend InputStream{

    private InputStream in;
    
    public BufferedInputStream(InputStream in){
        this.in = in;
    }
    
    byte[] buff;
    
    public int read(){
        // 扩展自己的功能
        // 调用成员变量in的相关方法
        in.read();
    }
    public int read(byte[] data, int off, int len){
        // 扩展自己的功能
        // 调用成员变量in方法
        in.read();
    }
}

// 使用装饰者模式
public static void main(String[] args){
    InputStream in = new FileInputStream(new File("/Users/data.txt"));
    StringBuilder sb = new StringBuilder();
    byte[] data = new byte[3];
    BufferedInputStream bis = new BufferedInputStream(in,5);
    int n = 0;
    while ((n = bis.read(data)) != -1) {
        sb.append(new String(data, 0, n));
    }
    System.out.println(sb);
    
}

10. 外观模式(Facade Pattern)—— 提供统一入口

提供了一个统一的接口(Facade [fəˈsɑːd]),用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。简单的讲,就是额外提供一个接口(外观接口),该接口封装原来的多个方法。

public class MyFacade{
    public void facade(){
        // 原来的方法1,2,3
    }
}

11. 享元(蝇量)模式(Flyweight Pattern)—— 实现对象的复用

运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次服用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,是一种对象结构性模式。

享元对象能做到共享的关键是区分了内部状态(共享)和 外 部 状 态 (独有的)

如JDK的String使用了享元模式

12. 代理模式(Proxy Pattern)—— 对象的间接访问

为另一个对象提供一个替身或占位符以访问这个对象。

JDK实现动态代理:

// 1. 定义原始类,必须基于接口。(JDK动态代理只能基于接口,
// 因为代理类是通过实现接口来实现的)
public interface Origin{
    public void method1();
}

public class OriginImpl implements Origin{
    public void method1(){
        //do something
    }
} 

// 实现InvocationHandler接口,其中的invoke方法就是代理类将会调用的方法。

public class OriginProxyHandler implements InvocationHandler{
    private Origin origin;

    // set方法和构造方法忽略
    
    /**
	proxy 当前的代理类
	method 当前调用的方法
    **/
    public Object invoke(Object proxy, Method method, Object[] args){
        // 如需要在代理对象执行原始对象的方法,需要将原始对象设为当前Handler的成员变量。
        // 前置方法
        // dosomething();
        // 原始对象
        Object result = method.invoke(origin, args);
        // 后置方法
        // dosomething();
        return result;
    }
}

// 生产代理对象
// clazz为当前代理的接口。如果是代理类的话,可调用Class的getInterfaces()方法
public static <T> T getProxyInstance(Class clazz, InvocationHandler invocationHandler) {
	return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, invocationHandler);
}

// 实际使用
public static void main(String[] args){
    Origin origin = new OriginImpl();
    OriginProxyHandler handler = new OriginProxyHandler(handler);
    Origin proxy = getProxyInstance(origin, handler);
    // 这里的方法将执行handler里的invoke方法。
    proxy.method1();
}

生成代理对象的主要流程:

  1. ProxyGenerator类的generateProxyClass方法,创建代理对象class的字节流。方法里核心的内容就是根据JVM规范创建class对象字节流(Write all the items of the "ClassFile" structure. See JVMS section 4.1.)
public static byte[] generateProxyClass(final String name,
                                        Class<?>[] interfaces,
                                        int accessFlags){


}
  1. 调用代理类Proxy的native方法defineClass0,将字节流生成class对象
private static native Class<?> defineClass0(ClassLoader loader, String name,
                                                byte[] b, int off, int len);
  1. 通过反射生成代理对象。
// 加载代理对象class
Class<?> cl = getProxyClass0(loader, intfs);
// 获取构造方法
final Constructor<?> cons = cl.getConstructor(constructorParams);
// 生成代理对象,h就是我们定义InvocationHandler
cons.newInstance(new Object[]{h});
  1. 实际动态生成的源码如下:
public final class $Proxy0 extends Proxy implements Origin {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void method1() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("Origin").getMethod("method1");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

行为型模式

13. 责任链模式(Chain of Responsibility Pattern)—— 请求的链式处理

当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式(Chain of Responsibility Pattern )。

public abstract class Handler{
    // 继任者
    protect Handler successor;

    public abstract void handleRequest();
}

public class Handler1 extends Handler{
    public abstract void handleRequest(){
        // handler1处理
        if(successor != null){
            successor.handleRequest();
        }
    }
}
public class Handler2 extends Handler{
    public abstract void handleRequest(){
        // handler2处理
        if(successor != null){
            successor.handleRequest();
        }
    }
}

public static void main(String[] args){
    Handler begin = new Handler1();
    Handler handler2 = new Handler2();
    begin.setSuccessor(handler2);
    begin.handleRequest();
}

14. 命令模式(Command Pattern)—— 请求发送者与接收者解轉

将请求封装成对象,这可以让你使用不同的请求、队列,或者日志请求来参数化其他对象。命令模式也可以支持撤销操作。

// 命令接口
public interface Command{
    public void execute();
}

// 调用者
public class Invoker{
    private Command command;

    public Invoker(Command command){
        this.command = command;
    }
    
    public void invoke(){
        command.execute();
    }
}

// 具体的命令类,执行具体的命令
public class ConcreteCommand implements Command{
    private int a;

    // 具体的动作
    public void execute(){
        // do1

        // do2
    }
}

public class App{
    public static void main(String[] args){
        Command command = new ConcreatedCommand();
        Invoker invoker = new Invoker(command);
        invoker.invoke();
    }
}

15. 解释器模式(Interprerer Pattern)—— 自定义语言的实现

建立解释器来解释语言中的句子。

16. 迭代器模式( Iterator Pattern)—— 遍历聚合对象中的元素

顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

// 迭代器接口
public interface Iterator{
    public boolean hasNext();
    public Object next();
}

// 生成迭代器接口
public interface Aggregate{
    public Iterator createIterator();
}

public class ConcreteIterator implements Iterator{
    // 具体的实现方法
}

public class ConcreteAggregate implements Aggregate{
    public Iterator createIterator(){
        return ConcreateIterator();
    }
}

public class Client{
    psvm(args){
        // 针对接口编程
        Aggregate aggregate = new ConcreteAggregate();
        Iterator iterator = aggregate.createIterator();
        // 迭代处理
    }
}

17. 中介者模式(Mediator Pattern)—— 协调多个对象之间的交互

用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

// 抽象中介者
public abstract class Mediator{
    // 中介所处理的事
    public void method1();
}

// 具体中介者
public class ConcreateMediator extends Mediator{
    List<Colleague> colleagues = new ArrayList();
    public void method1(){
        // 中介来点作用啦,一般是与其他同事交互
        // 对应的同事干活
        colleagues.get(0).method2();
    }
}

// 抽象同事类
public abstract class Colleague{
    protect Mediator mediator;

    public void method2();

    // 委托中介办事
    public void delegateMediator(){
        mediator.method1();
    }
}

// 具体同事类
public class ConcreateColleague extends Colleague{
    public void method2(){
        // 做自己的事啦
    }
}

public static void main(String[] args){
    Mediator mediator = new ConcreateMediator();
    Colleague colleague1 = new ConcreateColleague();
    colleague1.setMediator(mediator);
    colleague1.delegateMediator();
}

18. 备忘录模式(Memento Pattern)—— 撤销功能的实现

在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。

// 原始类,需要被 备忘录 对象记录的对象
public class GameObject{
    // 当前状态
    int state;

    // 记录
    public GameMemento save(){
        return new GameMemento(this.state);
    }

    public void restoreState(GameMemento gameMemento){
        this.state = gameMemento.state;
    }

}

// 备忘录
public class GameMemento{
    int state;
    public GameMemento(int state){
        this.state = state;
    }
}

psvm(){
    GameObject game = new GameObject();
    // 备忘录,记录当前状态
    GameMemento memento = game.save();
    // 回复当前状态
    game.restoreState(memento);
}

19. 观察者模式(Observer Pattern)—— 对象间的联动

定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

// 利用sdk提供的接口和类Observer、Observable来实现观察者模式

// 观察者
import java.util.Observable;
import java.util.Observer;
public class MyObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("我监听到对象啦!" + arg);
    }
}

// 主题
import java.util.Observable;
public class MySubject extends Observable {

    // 主题发生变化
    public void change(Object args){
        setChanged();
        notifyObservers(args);
    }

    public static void main(String[] args) {
        MySubject mySubject = new MySubject();
        mySubject.addObserver(new MyObserver());
        mySubject.change("你好!");
    }

}

20. 状态模式(State Pattern)—— 对象状态及其转换

运行对象在内部状态改变时改变的它的行为,对象看起来好像修改了它的类。

// 状态接口
public interface State{
    public void doA();
    public void doB();
}
// 具体的状态做具体的事
public class StateA implements State{
    public void doA(){
        
    }
    public void doB(){
        
    }
}

public class StateB implements State{
    public void doA(){
        
    }
    public void doB(){
        
    }
}

public class Client{
    public State state;

    // 不同状态下将有不同的行为
    public void doA{
        state.doA();
    }
    public void doB{
        state.doB();
    }
}

Client的state可有外部因素改变。增加setState()方法。
也可有内部状态决定。可这样实现:
public class StateA implements State{
    private Client client;

    public StateA(Client client){
        this.client = client;
    }
    
    public void doA(){
        // do A
        // 改变状态
        client.setState(new StateB());
    }
    public void doB(){
        
    }
}

21. 策略模式(Strategy Pattern)—— 算法的封装与切换

定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

22. 模板方法模式(Template Method Pattern)—— 定义算法的框架

在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。(工厂方法是模板方法的一种特殊版本)

23. 访问者模式(Visitor Pattern)—— 操作复杂对象结构

提供一个作用于某对象结构中的各元素的操作表示,它使得可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

public interface Visitor{
    public void visit(Element e);
}

public class ConcreateVisitorA() implements Visitor{
    public void visit(Element e){
        // 访问者A访问元素e
        e.getState();
    }
}

public class ConcreateVisitorB() implements Visitor{
    public void visit(Element e){
        // 访问者B访问元素e
        e.getState();
    }
}

public abstract class Element{
    public void getState();
    // 元素接受访问者访问
    public void accept(Visitor v){
        v.visit(this);
    }
}

public class ConcreateElementA extends Element{
    public void getState(){
        // 获取内部数据
    }
}

psvm(){
    Visitor visitor = new ConcreateVisitorA();
    Element element = new ConcreateElementA();
    element.accept(visitor);
}

其他

复合模式(Compound Pattern)

多个设计模式组合在一起,如MVC模式

参考文献

[1] Elisabeth Freeman, Eric Freeman, Bert Bates, Kathy Sierra, Elisabeth Robson 著. Head First 设计模式. O'ReillyTaiwan 公司译. 北京: 中国电力出版社,2007.

[2] 刘伟 著. 设计模式的艺术:软件开发人员内功修炼之道. 北京: 清华大学出版社,2013.