手把手教你23种设计模式

相关知识

简单工厂模式(不属于GoF 23 种设计模式)

工厂方法模式

抽象工厂模式

单例模式

原型模式

建造者模式

代理模式

门面模式(外观模式)

装饰器模式

享元模式

组合模式(整体-部分模式) 【透明式】【 安全式】

适配器模式 【类适配器】 【对象适配器】

桥接模式

模板方法模式

策略模式

责任链模式(职责链模式)

迭代器模式

命令模式

状态模式

备忘录模式(快照模式)

中介者模式(调停模式)

解释器模式

访问者模式

观察者模式

委派模式(不属于GoF 23 种设计模式)


学习设计模式前,强烈建议先学习软件设计七大原则(https://blog.csdn.net/samllwi...

相关知识

《设计模式:可复用面向对象软件的基础》(Design Patterns: Elements of Reusable Object-Oriented Software)一书有4位作者,这 4 位作者在软件开发领域里也以他们的“四人组”(Gang of Four,GoF)匿名著称。

23种设计模式按照目的分类:创建型模式、结构型模式和行为型模式

23种设计模式按照作用范围分类:类模式和对象型模式

设计模式分类如下表:

范围\目的 创建型模式 结构型模式 行为型模式
类模式 工厂方法(Factory Method)模式 (类)适配器(Adapter)模式 模板方法(TemplateMethod)模式
解释器(Interpreter)模式
对象模式 单例(Singleton)模式
原型(Prototype)模式
抽象工厂(AbstractFactory)模式
建造者(Builder)模式
代理(Proxy)模式
(对象)适配器(Adapter)模式
桥接(Bridge)模式
装饰(Decorator)模式
外观(Facade)模式
享元(Flyweight)模式
组合(Composite)模式
策略(Strategy)模式
命令(Command)模式
职责链(Chain of Responsibility)模式
状态(State)模式
观察者(Observer)模式
中介者(Mediator)模式
迭代器(Iterator)模式
访问者(Visitor)模式
备忘录(Memento)模式

把设计模式英文也写上的原因是到时候看源码后缀,可以看出使用了什么设计模式

简单工厂模式(不属于GoF 23 种设计模式)

含义:复杂对象不由用户直接创建,用工厂类进行创建

示例:

小米可以生产手机和电脑,都由工厂产生

public interface IProduct {
    void show();
}

public class MiComputer implements IProduct {
    public void show() {
        System.out.println("小米电脑");
    }
}

public class MiPhone implements IProduct {
    public void show() {
        System.out.println("小米手机");
    }
}

public class MiFactory {
    public static IProduct create(String type){
        if ("phone".equals(type)){
            return new MiPhone();
        }else if ("computer".equals(type)){
            return new MiComputer();
        }else {
            return null;
        }
    }
}

public class TestMain {
    public static void main(String[] args) {
        IProduct miPhone = MiFactory.create("phone");
        miPhone.show();
        IProduct miComputer= MiFactory.create("computer");
        miComputer.show();
    }
}

类图:

手把手教你23种设计模式_第1张图片

工厂方法模式

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

示例:

小米手机工厂生产手机,小米电脑工厂生产电脑

public interface IProduct {
    void show();
}

public class MiComputer implements IProduct {
    public void show() {
        System.out.println("小米电脑");
    }
}

public class MiPhone implements IProduct {
    public void show() {
        System.out.println("小米手机");
    }
}

public interface IFactory {
    IProduct create();
}

public class MiComputerFactory implements IFactory {
    public IProduct create() {
        return new MiComputer();
    }
}

public class MiPhoneFactory implements IFactory  {
    public IProduct create(){
       return new MiPhone();
    }
}

public class TestMain {
    public static void main(String[] args) {
        IProduct miPhone = new MiPhoneFactory().create();
        miPhone.show();
        IProduct miComputer = new MiComputerFactory().create();
        miComputer.show();
    }
}

类图:

手把手教你23种设计模式_第2张图片

抽象工厂模式

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

示例:

小米工厂可以生产手机和电脑;华为工厂也可以生产手机和电脑

public interface IProduct {
    void show();
}

public class HuaWeiComputer implements IProduct {
    public void show() {
        System.out.println("华为电脑");
    }
}

public class HuaWeiPhone implements IProduct {
    public void show() {
        System.out.println("华为手机");
    }
}

public class MiComputer implements IProduct {
    public void show() {
        System.out.println("小米电脑");
    }
}

public class MiPhone implements IProduct {
    public void show() {
        System.out.println("小米手机");
    }
}

public interface IFactory {
    IProduct createPhone();
    IProduct createComputer();
}

public class HuaWeiFactory implements IFactory {
    public IProduct createPhone() {
        return new HuaWeiPhone();
    }
    public IProduct createComputer() {
        return new HuaWeiComputer();
    }
}

public class MiFactory implements IFactory {
    public IProduct createPhone() {
        return new MiPhone();
    }
    public IProduct createComputer() {
        return new MiComputer();
    }
}

public class TestMain {
    public static void main(String[] args) {
        MiFactory miFactory = new MiFactory();
        IProduct miPhone = miFactory.createPhone();
        IProduct miComputer = miFactory.createComputer();
        miPhone.show();
        miComputer.show();
        HuaWeiFactory huaWeiFactory = new HuaWeiFactory();
        IProduct huaweiPhone = huaWeiFactory.createPhone();
        IProduct huaweiComputer = huaWeiFactory.createComputer();
        huaweiPhone.show();
        huaweiComputer.show();
    }
}

类图:

手把手教你23种设计模式_第3张图片

单例模式

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

单例模式技能要求:idea下要会多线程调试,控制每个线程的执行顺序

饿汉式

含义:类加载时进行实例化,没有线程安全问题。未使用的类也会占用内存空间

示例:【推荐】

public class HungrySingleton {
    private final static HungrySingleton INSTANCE = new HungrySingleton();

    private HungrySingleton() {
    }

    public static HungrySingleton getInstance() {
        return INSTANCE;
    }
}

懒汉式

含义:类加载时不会进行实例化,未使用的类不会占用内存空间

示例:

写法1:该写法会有线程安全问题,多个请求会同时进入”if (instance == null)“,并发时会产生多个示例,这也是要了解idea多线程调试。

public class LazySingleton1 {
    private  static LazySingleton1 instance;

    private LazySingleton1() {
    }

    public static LazySingleton1 getInstance() {
        if (instance == null) {
            instance = new LazySingleton1();
        }
        return instance;
    }
}

写法2:加锁,不会有线程安全问题,但会影响效率,每个请求都得进行排队

public class LazySingleton2 {
    private  static LazySingleton2 instance;

    private LazySingleton2() {
    }

    public static synchronized LazySingleton2 getInstance() {
        if (instance == null) {
            instance = new LazySingleton2();
        }
        return instance;
    }
}

写法3:将锁移到内部,可以提高效率,但是还有线程安全问题

public class LazySingleton3 {
    private  static LazySingleton3 instance;

    private LazySingleton3() {
    }

    public static  LazySingleton3 getInstance() {
        if (instance == null) {
            synchronized (LazySingleton3.class){
                instance = new LazySingleton3();
            }
        }
        return instance;
    }
}

写法4:双重检查锁,不仅提高效率,也避免了线程安全问题【推荐】

public class LazySingleton4 {
    private static volatile LazySingleton4 instance;

    private LazySingleton4() {
    }

    public static LazySingleton4 getInstance() {
        if (instance == null) {
            synchronized (LazySingleton4.class){
                if (instance == null){
                    instance = new LazySingleton4();
                }
            }
        }
        return instance;
    }
}

静态内部类方式

含义:静态内部类在加载时不会进行实例化,调用getInstance()时才会进行实例化。不会占用内存,也不会有线程安全问题【推荐】

示例:

public class StaticInnerSingleton {
    private StaticInnerSingleton() {
    }

    public static StaticInnerSingleton getInstance() {
        return InnerSingletonHolder.INSTANCE;
    }

    private static class InnerSingletonHolder {
        private static final StaticInnerSingleton INSTANCE = new StaticInnerSingleton();
    }
}

枚举方式

含义:不管何种单例模式,会有反射创建新实例的情况,但枚举对象有校验不能通过构造方法创建实例【推荐】

示例:

静态内部类通过反射会创建新实例

public class TestMain {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        StaticInnerSingleton instance = StaticInnerSingleton.getInstance();
        System.out.println(instance);
        Class clazz = StaticInnerSingleton.class;
        Constructor constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        StaticInnerSingleton staticInnerSingleton = constructor.newInstance();
        System.out.println(staticInnerSingleton);
    }
}

结果:

手把手教你23种设计模式_第4张图片

枚举单例

public enum EnumSingleton {
    INSTANCE;

    public static EnumSingleton getInstance() {
        return INSTANCE;
    }
}

public class TestMain {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        EnumSingleton instance = EnumSingleton.getInstance();
        System.out.println(instance);
        Constructor declaredConstructor = EnumSingleton.class.getDeclaredConstructor(String.class, int.class);
        declaredConstructor.setAccessible(true);
        EnumSingleton enumSingleton = declaredConstructor.newInstance();
        System.out.println(enumSingleton);
    }
}

结果:

手把手教你23种设计模式_第5张图片

容器方式

含义:使用时才去创建实例,不会浪费内存,无线程安全问题

示例:

public class ContainerSingleton {
    private ContainerSingleton() {

    }

    private static Map container = new HashMap<>();

    public static Object getInstance(String className) {
        if (container.get(className) == null) {
            synchronized (ContainerSingleton.class) {
                if (container.get(className) == null) {
                    Object instance = null;
                    try {
                        instance = Class.forName(className).newInstance();
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                    container.put(className, instance);
                }
            }
        }
        return container.get(className);
    }
}

序列化方式

含义:将实例存储为文件后,重新从文件读取会重新创建一个对象,包含”readResolve“方法读取时就不会重新创建对象

示例:

未添加”readResolve“方法时

public class SerializeSingleton implements Serializable {
    private final static SerializeSingleton INSTANCE = new SerializeSingleton();

    private SerializeSingleton() {
    }

    public static SerializeSingleton getInstance() {
        return INSTANCE;
    }
}

public class TestMain {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        SerializeSingleton instance = SerializeSingleton.getInstance();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("SerializeSingleton.obj"));
        objectOutputStream.writeObject(instance);
        objectOutputStream.flush();
        objectOutputStream.close();
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("SerializeSingleton.obj"));
        Object o = objectInputStream.readObject();
        objectInputStream.close();
        System.out.println(instance == o);
    }
}

结果:

手把手教你23种设计模式_第6张图片

添加”readResolve“方法时

public class SerializeSingleton implements Serializable {
    private final static SerializeSingleton INSTANCE = new SerializeSingleton();

    private SerializeSingleton() {
    }

    public static SerializeSingleton getInstance() {
        return INSTANCE;
    }

    private Object readResolve(){
        return INSTANCE;
    }
}

结果:

手把手教你23种设计模式_第7张图片

原型模式

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

原型模式的克隆分为浅克隆和深克隆。

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

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

示例:

每个人都有手机,克隆人的时候手机是独立的,不会去引用同一个手机

public class Phone implements Serializable {
}

@Data
public class PerSonPrototype implements Serializable {
    private String name;
    private Integer age;
    private Phone phone;

    /**
     * 深克隆
     * @return
     */
    public PerSonPrototype deepClone(){
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream outputStream = new ObjectOutputStream(bos);
            outputStream.writeObject(this);
            ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
            Object o = inputStream.readObject();
            return (PerSonPrototype) o;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 浅克隆
     * @return
     */
    public PerSonPrototype shallowClone(){
        PerSonPrototype perSonPrototype = new PerSonPrototype();
        perSonPrototype.setName(this.getName());
        perSonPrototype.setAge(this.getAge());
        perSonPrototype.setPhone(this.getPhone());
        return perSonPrototype;
    }
}

public class TestMain {
    public static void main(String[] args) {
        PerSonPrototype perSonPrototype = new PerSonPrototype();
        perSonPrototype.setName("zhang");
        perSonPrototype.setAge(10);
        perSonPrototype.setPhone(new Phone());
        PerSonPrototype deepCloneObj = perSonPrototype.deepClone();
        PerSonPrototype shallowCloneObj = perSonPrototype.shallowClone();
        System.out.println(perSonPrototype.getPhone() == deepCloneObj.getPhone());
        System.out.println(perSonPrototype.getPhone() == shallowCloneObj.getPhone());
    }
}

结果:

手把手教你23种设计模式_第8张图片

类图:

手把手教你23种设计模式_第9张图片

建造者模式

含义:将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示

mybatis-plus中可以通过lambada表达式构建查询语句,就是使用了建造者模式

示例:

汽车工厂通过工程师来组装汽车

/**
 * 汽车
 *
 * @author lipangpang
 * @date 2021/12/13
 * @description
 */
@Data
public class Car {
    /**
     * 轮胎
     */
    private String tyre;
    /**
     * 发动机
     */
    private String engine;
    /**
     * 颜色
     */
    private String color;

}

/**
 * 工程师
 *
 * @author lipangpang
 * @date 2021/12/13
 * @description
 */
public abstract class IBuilder {
    protected Car car = new Car();

    public abstract void buildTyre();

    public abstract void buildEngine();

    public abstract void buildColor();

    public Car getCar() {
        return car;
    }
}

/**
 * @author lipangpang
 * @date 2021/12/13
 * @description
 */
public class Builder extends IBuilder {

    @Override
    public void buildTyre() {
        car.setTyre("玛吉斯轮胎");
    }

    @Override
    public void buildEngine() {
        car.setEngine("蓝鲸发动机");
    }

    @Override
    public void buildColor() {
        car.setColor("红色");
    }
}

/**
 * 汽车工厂
 *
 * @author lipangpang
 * @date 2021/12/13
 * @description
 */
public class CarFactory {
    private IBuilder builder;

    public CarFactory(IBuilder builder) {
        this.builder = builder;
    }

    public Car build(){
        builder.buildTyre();
        builder.buildEngine();
        builder.buildColor();
        return builder.getCar();
    }
}

public class TestMain {
    public static void main(String[] args) {
        CarFactory carFactory = new CarFactory(new Builder());
        Car car = carFactory.build();
        System.out.println(car);
    }
}

类图:

手把手教你23种设计模式_第10张图片

代理模式

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

为访问对象和目标对象之间的中介。

根据代理的创建时期,代理模式分为静态代理和动态代理。

静态:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。

动态:在程序运行时,运用反射机制动态创建而成

示例:

静态代理

人通过中介购买房子,中介先列出房子相关信息,人购买房子,中介收取中介费

public interface IPerson {
    void buy();
}

public class Person implements IPerson {
    @Override
    public void buy() {
        System.out.println("顾客买房子");
    }
}

public class Proxy implements IPerson{

    private IPerson person;

    public Proxy(IPerson person) {
        this.person = person;
    }

    @Override
    public void buy() {
        before();
        person.buy();
        after();
    }

    public void before(){
        System.out.println("列出房子相关信息");
    }

    public void after(){
        System.out.println("交易成功,收取中介费");
    }
}

public class TestMain {
    public static void main(String[] args) {
        IPerson person = new Person();
        Proxy proxy = new Proxy(person);
        proxy.buy();
    }
}

类图:

手把手教你23种设计模式_第11张图片

实例:

动态代理实现

public interface IPerson {
    void buy();
}

public class Person implements IPerson {
    @Override
    public void buy() {
        System.out.println("顾客买房子");
    }
}

public class ProxyInvocationHandler implements InvocationHandler {
    private Object target;

    public ProxyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("列出房子相关信息");
        Object result = method.invoke(target, args);
        System.out.println("交易成功,收取中介费");
        return result;
    }
}

public class TestMain {
    public static void main(String[] args) {
        IPerson person = new Person();
        ProxyInvocationHandler handler = new ProxyInvocationHandler(person);
        IPerson proxyInstance = (IPerson) Proxy.newProxyInstance(person.getClass().getClassLoader(),                  person.getClass().getInterfaces(), handler);
        proxyInstance.buy();
    }
}

类图:

手把手教你23种设计模式_第12张图片

门面模式(外观模式)

含义:门面模式也叫外观模式,通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。

门店模式是一种静态的代理模式。

示例:

用户再商城购买商品,会在订单系统先创建订单,然后库存系统扣减库存,再从物流系统发货

public class OrderSystem {
    public void createOrder(){
        System.out.println("订单系统先创建订单");
    }
}

public class StockSystem {
    public void decreaseStock(){
        System.out.println("库存系统扣减库存");
    }
}

public class LogisticsSystem {
    public void addSalesVolume(){
        System.out.println("物流系统发货");
    }
}

public class MallFacade {
    private OrderSystem orderSystem = new OrderSystem();
    private StockSystem stockSystem = new StockSystem();
    private LogisticsSystem logisticsSystem = new LogisticsSystem();

    public void buyGoods(){
        orderSystem.createOrder();;
        stockSystem.decreaseStock();
        logisticsSystem.addSalesVolume();
    }
}

public class TestMain {
    public static void main(String[] args) {
        MallFacade mallFacade = new MallFacade();
        mallFacade.buyGoods();
    }
}

类图:

手把手教你23种设计模式_第13张图片

装饰器模式

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

java中流的封装是一种装饰器模式的实现,如下

BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(""));

示例:

水果蛋糕,在纯蛋糕的基础上可以增加芒果、草莓和樱桃等。

/**
 * 蛋糕接口
 * @author lipangpang
 * @date 2021/12/15
 * @description
 */
public interface ICake {
    String getInfo();
}

/**
 * 纯蛋糕
 * @author lipangpang
 * @date 2021/12/15
 * @description
 */
public class BaseCake implements ICake {
    @Override
    public String getInfo() {
        return "纯蛋糕";
    }
}

/**
 * 水果装饰器
 * @author lipangpang
 * @date 2021/12/15
 * @description
 */
public class FruitDecorator implements ICake {
    private ICake iCake;

    public FruitDecorator(ICake iCake) {
        this.iCake = iCake;
    }

    @Override
    public String getInfo() {
        return this.iCake.getInfo();
    }
}

/**
 * 芒果装饰器
 * @author lipangpang
 * @date 2021/12/15
 * @description
 */
public class MangoDecorator extends FruitDecorator {
    public MangoDecorator(ICake iCake) {
        super(iCake);
    }

    @Override
    public String getInfo() {
        return super.getInfo() + " + 芒果";
    }
}

/**
 * 草莓装饰器
 *
 * @author lipangpang
 * @date 2021/12/15
 * @description
 */
public class StrawberryDecorator extends FruitDecorator {
    public StrawberryDecorator(ICake iCake) {
        super(iCake);
    }

    @Override
    public String getInfo() {
        return super.getInfo() + " + 草莓";
    }
}

/**
 * 樱桃装饰器
 * @author lipangpang
 * @date 2021/12/15
 * @description
 */
public class CherryDecorator extends FruitDecorator {
    public CherryDecorator(ICake iCake) {
        super(iCake);
    }

    @Override
    public String getInfo() {
        return super.getInfo() + " + 樱桃";
    }
}

public class TestMain {
    public static void main(String[] args)  {
        ICake baseCake = new BaseCake();
        System.out.println(baseCake.getInfo());
        MangoDecorator mangoDecorator = new MangoDecorator(baseCake);
        System.out.println(mangoDecorator.getInfo());
        StrawberryDecorator strawberryDecorator = new StrawberryDecorator(mangoDecorator);
        System.out.println(strawberryDecorator.getInfo());
        CherryDecorator cherryDecorator = new CherryDecorator(strawberryDecorator);
        System.out.println(cherryDecorator.getInfo());
    }
}

结果:

手把手教你23种设计模式_第14张图片

类图:

手把手教你23种设计模式_第15张图片

享元模式

含义:运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似

类的开销,从而提高系统资源的利用率。

享元模式包含的对象有两种状态:内部状态和外部状态;

内部状态指对象共享出来的信息,存储在享元信息内部,并且不回随环境的改变而改变;

外部状态指对象得以依赖的一个标记,随环境的改变而改变,不可共享。

示例:

火车站现在都有投放按摩椅,椅子是固定的,去消费的人不是固定的

/**
 * 游客
 *
 * @author lipangpang
 * @date 2021/12/16
 * @description
 */
public class Person {
    /**
     * 游客姓名
     */
    private String name;


    public Person(String name) {
        this.name = name;
    }

    public String buyService() {
        return name + "花钱购买了";
    }
}

/**
 * 按摩椅接口
 *
 * @author lipangpang
 * @date 2021/12/16
 * @description
 */
public interface IChair {
    /**
     * 获取按摩椅信息
     *
     * @return
     */
    String getInfo(Person person);
}

/**
 * 按摩椅
 *
 * @author lipangpang
 * @date 2021/12/16
 * @description
 */
public class Chair implements IChair {

    /**
     * 编号
     */
    private String chairNo;

    public Chair(String chairNo) {
        this.chairNo = chairNo;
    }

    @Override
    public String getInfo(Person person) {
        return person.buyService() + "按摩椅" + chairNo + "的服务";
    }
}

/**
 * 按摩椅工厂
 *
 * @author lipangpang
 * @date 2021/12/16
 * @description
 */
public class ChairFactory {
    private Map chairNo2Chair = new HashMap<>();

    public ChairFactory() {
        for (int i = 1; i <= 5; i++) {
            String chairNo = "A00" + i;
            chairNo2Chair.put(chairNo, new Chair(chairNo));
        }
    }

    public IChair getChair(String chairNo) {
        return chairNo2Chair.get(chairNo);
    }
}

public class TestMain {
    public static void main(String[] args) {
        ChairFactory chairFactory = new ChairFactory();
        IChair chair1 = chairFactory.getChair("A001");
        IChair chair11 = chairFactory.getChair("A001");
        IChair chair2 = chairFactory.getChair("A002");
        System.out.println(chair1.getInfo(new Person("zhang")));
        System.out.println(chair11.getInfo(new Person("li")));
        System.out.println(chair2.getInfo(new Person("wang")));
    }
}

类图:

手把手教你23种设计模式_第16张图片

组合模式(整体-部分模式)

含义:又叫作整体-部分(Part-Whole)模式,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户

对单个对象和组合对象具有一致的访问性。将对象组合到树形结构中,有根节点、树枝节点和叶子节点,树形结构图如下。

手把手教你23种设计模式_第17张图片

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

透明式:

示例:文件系统,包含文件和文件夹。文件和文件都继承同一个抽象接口,抽象接口包含所有方法。

/**
 * 安全模式-文件系统-目录
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public abstract class Directory {
    protected String name;

    public Directory(String name) {
        this.name = name;
    }

    public void add(Directory directory) {
        throw new UnsupportedOperationException("不支持增加操作");
    }

    public void remove(Directory directory) {
        throw new UnsupportedOperationException("不支持移出操作");
    }

    public abstract void print();

}

/**
 * 安全模式-文件系统-文件
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public class File extends Directory {
    public File(String name) {
        super(name);
    }

    @Override
    public void print() {
        System.out.println("    文件 " + this.name);
    }
}

/**
 * 安全模式-文件系统-文件夹
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public class Folder extends Directory {
    private List items = new ArrayList<>();

    public Folder(String name) {
        super(name);
    }

    @Override
    public void print() {
        System.out.println("文件夹 " + this.name + "==>");
        for (Directory item : items) {
            item.print();
        }
    }

    @Override
    public void add(Directory directory) {
        items.add(directory);
    }

    @Override
    public void remove(Directory directory) {
        items.remove(directory);
    }
}

public class TestMain {
    public static void main(String[] args) {
        Directory root = new Folder("C盘");
        File idea = new File("idea开发工具");
        root.add(idea);
        Directory musicTool = new Folder("音乐工具文件夹");
        File kugouMusic = new File("酷狗音乐软件");
        File qqMusic = new File("QQ音乐软件");
        musicTool.add(kugouMusic);
        musicTool.add(qqMusic);
        root.add(musicTool);
        root.print();
    }
}

结果:

手把手教你23种设计模式_第18张图片

类图:

手把手教你23种设计模式_第19张图片

安全式:

示例:文件系统,包含文件和文件夹。文件和文件都继承同一个抽象接口,抽象接口只包含公共方法。

/**
 * 安全模式-文件系统-目录
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public abstract class Directory {
    protected String name;

    public Directory(String name) {
        this.name = name;
    }


    public abstract void print();

}

/**
 * 安全模式-文件系统-文件
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public class File extends Directory {
    public File(String name) {
        super(name);
    }

    @Override
    public void print() {
        System.out.println("===>文件 " + this.name);
    }
}

/**
 * 安全模式-文件系统-文件夹
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public class Folder extends Directory {
    private List items = new ArrayList<>();

    public Folder(String name) {
        super(name);
    }


    @Override
    public void print() {
        System.out.println("文件夹 " + this.name);
        for (Directory item : items) {
            item.print();
        }
    }

    public void add(Directory directory) {
        items.add(directory);
    }

    public void remove(Directory directory) {
        items.remove(directory);
    }
}

public class TestMain {
    public static void main(String[] args) {
        Folder root = new Folder("C盘");
        File idea = new File("idea开发工具");
        root.add(idea);
        Folder musicTool = new Folder("音乐工具文件夹");
        File kugouMusic = new File("酷狗音乐软件");
        File qqMusic = new File("QQ音乐软件");
        musicTool.add(kugouMusic);
        musicTool.add(qqMusic);
        root.add(musicTool);
        root.print();
    }
}

结果:

手把手教你23种设计模式_第20张图片

类图:

手把手教你23种设计模式_第21张图片

适配器模式

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

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

  1. 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
  2. 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
  3. 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式

    访问适配者。

类适配器:

示例:

电源适配器,可以将220v交流电转换成5v或者10v的直流电

/**
 * 直流电目标
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public interface IDirectTarget {
    /**
     * 获取5v直流电
     *
     * @return
     */
    int getDirect5v();

    /**
     * 获取10v直流电
     *
     * @return
     */
    int getDirect10v();
}

/**
 * 交流电220v适配者
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public class AC220Adaptee {

    /**
     * 获取220v交流电
     *
     * @return
     */
    public int getAC220v() {
        return 220;
    }
}

/**
 * 电源适配器
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public class PowerAdapter extends AC220Adaptee implements IDirectTarget {
    @Override
    public int getDirect5v() {
        return getAC220v() / 44;
    }

    @Override
    public int getDirect10v() {
        return getAC220v() / 22;
    }
}

public class TestMain {
    public static void main(String[] args) {
        PowerAdapter powerAdapter = new PowerAdapter();
        System.out.println(powerAdapter.getDirect5v());
        System.out.println(powerAdapter.getDirect10v());
    }
}

类图:

手把手教你23种设计模式_第22张图片

对象适配器:

示例:

电源适配器,可以将220v交流电转换成5v或者10v的直流电

/**
 * 直流电目标
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public interface IDirectTarget {
    /**
     * 获取5v直流电
     *
     * @return
     */
    int getDirect5v();

    /**
     * 获取10v直流电
     *
     * @return
     */
    int getDirect10v();
}

/**
 * 交流电220v适配者
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public class AC220Adaptee {

    /**
     * 获取220v交流电
     *
     * @return
     */
    public int getAC220v() {
        return 220;
    }
}

/**
 * 电源适配器
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public class PowerAdapter implements IDirectTarget {

    private AC220Adaptee ac220Adaptee;

    public PowerAdapter(AC220Adaptee ac220Adaptee) {
        this.ac220Adaptee = ac220Adaptee;
    }

    @Override
    public int getDirect5v() {
        return ac220Adaptee.getAC220v() / 44;
    }

    @Override
    public int getDirect10v() {
        return ac220Adaptee.getAC220v() / 22;
    }
}

public class TestMain {
    public static void main(String[] args) {
        PowerAdapter powerAdapter = new PowerAdapter(new AC220Adaptee());
        System.out.println(powerAdapter.getDirect5v());
        System.out.println(powerAdapter.getDirect10v());
    }
}

类图:

手把手教你23种设计模式_第23张图片

桥接模式

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

度。

桥接(Bridge)模式包含以下主要角色。

  1. 抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
  2. 扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务

    方法。

  3. 实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
  4. 具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。

示例:

汽车有红色和白色,摩托车有红色和白色,当要其中一种对象时,不会创建四种对象类,而是通过组合的方式,创建两种对象类。

/**
 * 颜色接口
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public interface IColor {
    String getColor();
}

public class Red implements IColor {
    @Override
    public String getColor() {
        return "红色";
    }
}

public class White implements IColor {
    @Override
    public String getColor() {
        return "白色";
    }
}

/**
 * 交通工具桥接类
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public abstract class IVehicle {
    protected IColor color;

    public IVehicle(IColor color) {
        this.color = color;
    }

    public abstract void printInfo();
}

/**
 * 摩托车
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public class Motorcycle extends IVehicle {
    public Motorcycle(IColor color) {
        super(color);
    }

    @Override
    public void printInfo() {
        System.out.println("摩托" + color.getColor());
    }
}

/**
 * 汽车
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public class Car extends IVehicle {
    public Car(IColor color) {
        super(color);
    }

    @Override
    public void printInfo() {
        System.out.println("汽车" + color.getColor());
    }
}

public class TestMain {
    public static void main(String[] args) {
        Car car = new Car(new White());
        car.printInfo();
        car = new Car(new Red());
        car.printInfo();
    }
}

类图:

手把手教你23种设计模式_第24张图片

模板方法模式

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

定步骤。

模板方法模式包含以下角色。

  1. 抽象模板

    1. 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
    2. 基本方法:是整个算法中的一个步骤,包含以下几种类型。

      1. 抽象方法:在抽象类中声明,由具体子类实现。
      2. 具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。
      3. 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。
  2. 具体实现

示例:

用户在手机上购买商品流程,先挑选商品,创建订单,支付,然后根据需要时上门自提还是骑手配送。

/**
 * 购物模板类
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public abstract class ShoppingTemplate {
    protected abstract String searchProduct();

    final String createOrder() {
        return "创建订单";
    }

    final String payOrder() {
        return "支付订单";
    }

    /**
     * 钩子方法,用于调整业务流程
     *
     * @return
     */
    protected abstract boolean isLogistics();

    final String selfMention() {
        return "到门店自提";
    }

    final String Logistics() {
        return "骑手配送上门";
    }

    public void shopping() {
        String result = searchProduct() + ">" + createOrder() + ">" + payOrder();
        if (isLogistics()) {
            result += ">" + Logistics();
        } else {
            result += ">" + selfMention();
        }
        System.out.println(result);
    }
}

/**
 * 消费者购物类
 *
 * @author lipangpang
 * @date 2021/12/18
 * @description
 */
public class CustomerShopping extends ShoppingTemplate {
    private String productName;
    private boolean isLogistics;

    public CustomerShopping(String productName, boolean isLogistics) {
        this.productName = productName;
        this.isLogistics = isLogistics;
    }

    @Override
    protected String searchProduct() {
        return this.productName;
    }

    @Override
    protected boolean isLogistics() {
        return this.isLogistics;
    }
}

public class TestMain {
    public static void main(String[] args) {
        System.out.println("顾客1订单信息===");
        CustomerShopping customerShopping1 = new CustomerShopping("苹果",true);
        customerShopping1.shopping();
        System.out.println("顾客2订单信息===");
        CustomerShopping customerShopping2 = new CustomerShopping("香蕉",false);
        customerShopping2.shopping();
    }
}

结果:

手把手教你23种设计模式_第25张图片

类图:

手把手教你23种设计模式_第26张图片

策略模式

含义:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。

策略模式结构如下。

  1. 抽象策略类
  2. 具体策略类
  3. 环境类

示例:每个人都周末都有不同的安排,比如健身、看电影和学习等。

/**
 * 活动抽象策略类
 *
 * @author lipangpang
 * @date 2021/12/22
 * @description
 */
public interface IActivity {
    /**
     * 策略方法
     */
    void execute();
}

public class BodyBuildingActivity implements IActivity {
    @Override
    public void execute() {
        System.out.println("周末健身");
    }
}

public class MovieActivity implements IActivity {
    @Override
    public void execute() {
        System.out.println("周末看电影");
    }
}

public class StudyActivity implements IActivity {
    @Override
    public void execute() {
        System.out.println("周末学习");
    }
}

public class TestMain {
    public static void main(String[] args) {
        StrategyContext strategyContext = new StrategyContext(new MovieActivity());
        strategyContext.executeStrategy();
    }
}

结果:

周末看电影

类图:

手把手教你23种设计模式_第27张图片

责任链模式(职责链模式)

含义:为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条

链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

责任链模式结构如下。

  1. 抽象处理者
  2. 具体处理者
  3. 客户类

示例:去店铺买东西,导购员有打9折权限,储备店长有打8折权限,店长有打7折权限。

/**
 * 员工抽象类
 *
 * @author lipangpang
 * @date 2021/12/22
 * @description
 */
public abstract class Handler {
    /**
     * 下一执行人
     */
    private Handler next;

    public Handler getNext() {
        return next;
    }

    public void setNext(Handler next) {
        this.next = next;
    }

    /**
     * 处理请求方法
     *
     * @param discount
     */
    abstract void handlerDiscount(Integer discount);
}

/**
 * 导购员
 *
 * @author lipangpang
 * @date 2021/12/22
 * @description
 */
public class ShoppingGuide extends Handler {
    @Override
    void handlerDiscount(Integer discount) {
        if (discount >= 9) {
            System.out.println("导购员打9折");
        } else {
            if (this.getNext() == null) {
                System.out.println("导购员不能进行打" + discount + "折");
            } else {
                this.getNext().handlerDiscount(discount);
            }
        }
    }
}

/**
 * 储备店长
 *
 * @author lipangpang
 * @date 2021/12/22
 * @description
 */
public class ReserverManager extends Handler {
    @Override
    void handlerDiscount(Integer discount) {
        if (discount >= 8) {
            System.out.println("储备店长打8折");
        } else {
            if (this.getNext() == null) {
                System.out.println("储备店长不能进行打" + discount + "折");
            } else {
                this.getNext().handlerDiscount(discount);
            }
        }
    }
}

/**
 * 店长
 *
 * @author lipangpang
 * @date 2021/12/22
 * @description
 */
public class Manager extends Handler {
    @Override
    void handlerDiscount(Integer discount) {
        if (discount >= 7) {
            System.out.println("店长打7折");
        } else {
            if (this.getNext() == null) {
                System.out.println("店长不能进行打" + discount + "折");
            } else {
                this.getNext().handlerDiscount(discount);
            }
        }
    }
}

public class TestMain {
    public static void main(String[] args) {
        ShoppingGuide shoppingGuide = new ShoppingGuide();
        ReserverManager reserverManager = new ReserverManager();
        Manager manager = new Manager();
        shoppingGuide.setNext(reserverManager);
        reserverManager.setNext(manager);
        shoppingGuide.handlerDiscount(8);
    }
}

结果:

储备店长打8折

类图:

手把手教你23种设计模式_第28张图片

迭代器模式

含义:提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。

迭代器模式结构如下。

  1. 抽象聚合角色:义存储、添加、删除聚合对象以及创建迭代器对象的接口。
  2. 具体聚合角色:实现抽象聚合类,返回一个具体迭代器的实例。
  3. 抽象迭代器角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
  4. 具体迭代器角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

示例:实现类似List的功能,可以增加、删除元素,获取迭代器,遍历元素。

/**
 * 抽象集合接口
 * @author lipangpang
 * @date 2021/12/25
 * @description
 */
public interface MyList {
    /**
     * 增加元素
     *
     * @param o
     */
    void add(Object o);

    /**
     * 删除元素
     *
     * @param o
     */
    void remove(Object o);

    /**
     * 获取迭代器
     *
     * @return
     */
    Iterator iterator();
}

/**
 * 抽象聚合实现类
 * @author lipangpang
 * @date 2021/12/25
 * @description
 */
public class MyListImpl implements MyList {
    private List list = new ArrayList<>();
    @Override
    public void add(Object o) {
        list.add(o);
    }

    @Override
    public void remove(Object o) {
        list.remove(o);
    }

    @Override
    public Iterator iterator() {
        return new IteratorImpl(list);
    }
}

/**
 * 迭代器接口
 *
 * @author lipangpang
 * @date 2021/12/25
 * @description
 */
public interface Iterator {
    /**
     * 获取第一个元素
     *
     * @return
     */
    Object first();

    /**
     * 获取下一个元素
     *
     * @return
     */
    Object next();

    /**
     * 是否有下一个元素
     *
     * @return
     */
    boolean hasNext();
}

/**
 * 迭代器实现类
 *
 * @author lipangpang
 * @date 2021/12/25
 * @description
 */
public class IteratorImpl implements Iterator {
    private List list;
    private Integer index = -1;

    public IteratorImpl(List list) {
        this.list = list;
    }

    @Override
    public Object first() {
        index = 0;
        if (list.size() == 0){
            throw new NoSuchElementException("没有元素");
        }
        return list.get(index);
    }

    @Override
    public Object next() {
        if (index == list.size()){
            throw new NoSuchElementException("没有元素");
        }
        return list.get(index);
    }

    @Override
    public boolean hasNext() {
        index++;
        return index < list.size();
    }
}

public class TestMain {
    public static void main(String[] args) {
        MyList myList = new MyListImpl();
        myList.add("a");
        myList.add("b");
        myList.add("c");
        Iterator iterator = myList.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
} 
 

结果:

a
b
c

类图:

手把手教你23种设计模式_第29张图片

命令模式

含义:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令

对象进行储存、传递、调用、增加与管理。

命令模式结构如下。

  1. 抽象命令类(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法 execute()。
  2. 具体命令类(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要

    执行的操作。

  3. 实现者/接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
  4. 调用者/请求者(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访

    问接收者。

示例:每天早上家长叫孩子起床、刷牙

/**
 * 命令接口
 *
 * @author lipangpang
 * @date 2021/12/25
 * @description
 */
public interface ICommand {
    void execute();
}

/**
 * 起床命令
 *
 * @author lipangpang
 * @date 2021/12/25
 * @description
 */
public class GetUpCommand implements ICommand {
    private ChildrenReceiver childrenReceiver;

    public GetUpCommand(ChildrenReceiver childrenReceiver) {
        this.childrenReceiver = childrenReceiver;
    }

    @Override
    public void execute() {
        childrenReceiver.getUp();
    }
}

/**
 * 刷牙命令
 *
 * @author lipangpang
 * @date 2021/12/25
 * @description
 */
public class BrushTeethCommand implements ICommand {
    private ChildrenReceiver childrenReceiver;

    public BrushTeethCommand(ChildrenReceiver childrenReceiver) {
        this.childrenReceiver = childrenReceiver;
    }

    @Override
    public void execute() {
        childrenReceiver.brushTeeth();
    }
}

/**
 * 孩子接收者
 *
 * @author lipangpang
 * @date 2021/12/25
 * @description
 */
public class ChildrenReceiver {

    public void getUp() {
        System.out.println("起床");
    }

    public void brushTeeth() {
        System.out.println("刷牙");
    }
}

/**
 * 家长调用者
 *
 * @author lipangpang
 * @date 2021/12/25
 * @description
 */
public class ParentInvoker {
    private ICommand command;

    public ParentInvoker() {

    }

    public ICommand getCommand() {
        return command;
    }

    public void setCommand(ICommand command) {
        this.command = command;
    }

    public void call() {
        command.execute();
    }
}

public class TestMain {
    public static void main(String[] args) {
        ChildrenReceiver childrenReceiver = new ChildrenReceiver();
        GetUpCommand getUpCommand = new GetUpCommand(childrenReceiver);
        BrushTeethCommand brushTeethCommand = new BrushTeethCommand(childrenReceiver);
        ParentInvoker parentInvoker = new ParentInvoker();
        parentInvoker.setCommand(getUpCommand);
        parentInvoker.call();
        parentInvoker.setCommand(brushTeethCommand);
        parentInvoker.call();
    }
}

结果:

起床
刷牙

类图:

手把手教你23种设计模式_第30张图片

状态模式

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

状态模式结构如下。

  1. 环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
  2. 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
  3. 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。

示例:订单支付状态有待支付、已支付和已退款,待支付才能进行支付,已支付才能进行退款。

/**
 * 抽象状态类
 *
 * @author lipangpang
 * @date 2021/12/26
 * @description
 */
public abstract class State {
    /**
     * 状态名称
     */
    protected String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

/**
 * 待支付状态
 *
 * @author lipangpang
 * @date 2021/12/26
 * @description
 */
public class UnPayState extends State {
    public UnPayState() {
        this.name = "待支付状态";
        System.out.println("当前订单状态:" + this.name);
    }

    /**
     * 支付操作
     *
     * @param orderContext
     */
    public void pay(OrderContext orderContext) {

        orderContext.setState(new PayedState());
    }
}

/**
 * 已支付状态
 *
 * @author lipangpang
 * @date 2021/12/26
 * @description
 */
public class PayedState extends State {
    public PayedState() {
        this.name = "已支付状态";
        System.out.println("当前订单状态:" + this.name);
    }

    /**
     * 退款操作
     *
     * @param orderContext
     */
    public void refund(OrderContext orderContext) {
        orderContext.setState(new RefundedState());
    }
}

/**
 * 已退款状态
 *
 * @author lipangpang
 * @date 2021/12/26
 * @description
 */
public class RefundedState extends State {
    public RefundedState() {
        this.name = "已退款状态";
        System.out.println("当前订单状态:" + this.name);
    }
}

/**
 * 订单环境类
 *
 * @author lipangpang
 * @date 2021/12/26
 * @description
 */
public class OrderContext {
    private State state;

    public OrderContext() {
        this.state = new UnPayState();
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    /**
     * 支付操作
     */
    public void pay() {
        System.out.println("去支付");
        if ("待支付状态".equals(state.getName())){
            ((UnPayState)state).pay(this);
        }else {
            System.out.println("待支付状态才能去支付");
        }
    }

    /**
     * 退款操作
     */
    public void refund() {
        System.out.println("去退款");
        if ("已支付状态".equals(state.getName())){
            ((PayedState)state).refund(this);
        }else {
            System.out.println("已支付状态才能去退款");
        }
    }
}

public class TestMain {
    public static void main(String[] args) {
        OrderContext orderContext = new OrderContext();
        orderContext.pay();
        orderContext.refund();
    }
}

结果:

当前订单状态:待支付状态
去支付
当前订单状态:已支付状态
去退款
当前订单状态:已退款状态

类图:

手把手教你23种设计模式_第31张图片

备忘录模式(快照模式)

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

存的状态。

备忘录模式结构如下。

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

    访问备忘录里的所有信息。

  2. 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
  3. 管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。

示例:用户在编辑文档的时候,每次保存都会存储一份当前数据的状态当做备忘录,按下撤销键可以返回上一个状态。

/**
 * 备忘录数据
 *
 * @author lipangpang
 * @date 2021/12/26
 * @description
 */
public class Memento {
    private String data;

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
}

/**
 * 备忘录管理者
 *
 * @author lipangpang
 * @date 2021/12/26
 * @description
 */
public class Caretaker {
    /**
     * 所有备忘录数据
     */
    private Stack datas = new Stack<>();

    /**
     * 保存备忘录数据
     *
     * @return
     */
    public Memento getData() {
        return datas.pop();
    }

    /**
     * 获取备忘录数据
     *
     * @param memento
     * @return
     */
    public Memento saveData(Memento memento) {
        return datas.push(memento);
    }
}

/**
 * 编辑文档发起者
 *
 * @author lipangpang
 * @date 2021/12/26
 * @description
 */
public class EditOriginator {
    /**
     * 用户当前编辑的文本
     */
    private String text;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    /**
     * 创建备忘录数据
     */
    public Memento createMemento() {
        Memento memento = new Memento();
        memento.setData(text);
        return memento;
    }
}

public class TestMain {
    public static void main(String[] args) {
        EditOriginator editOriginator = new EditOriginator();
        Caretaker caretaker = new Caretaker();
        editOriginator.setText("第一次编辑数据");
        caretaker.saveData(editOriginator.createMemento());
        editOriginator.setText("第二次编辑数据");
        System.out.println("当前数据:" + editOriginator.getText());
        editOriginator.setText(caretaker.getData().getData());
        System.out.println("回滚后数据:" + editOriginator.getText());
    }
}

结果:

当前数据:第二次编辑数据
回滚后数据:第一次编辑数据

类图:

手把手教你23种设计模式_第32张图片

中介者模式(调停模式)

含义:定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互

中介者模式结构如下。

  1. 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
  2. 具体中介者(Concrete Mediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因

    此它依赖于同事角色。

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

    的公共功能。

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

示例:群聊的时候,只要有一个人发消息,群众的所有人可以接受到消息。

/**
 * 同事接口
 *
 * @author lipangpang
 * @date 2021/12/27
 * @description
 */
public abstract class IColleague {
    /**
     * 聊天室中介者
     */
    protected IGroupChatMediator groupChatMediator;
    /**
     * 同事姓名
     */
    private String name;
    /**
     * 同事发送的消息
     */
    private String msg;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public IColleague(IGroupChatMediator groupChatMediator, String name) {
        this.groupChatMediator = groupChatMediator;
        this.name = name;
    }

    /**
     * 发送消息
     *
     * @param msg
     */
    abstract void sendMsg(String msg);

    /**
     * 接受消息
     *
     * @param msg
     */
    abstract void receiveMsg(String msg);
}

/**
 * 同事
 *
 * @author lipangpang
 * @date 2021/12/27
 * @description
 */
public class Colleague extends IColleague {
    public Colleague(IGroupChatMediator groupChatMediator, String name) {
        super(groupChatMediator, name);
    }

    @Override
    void sendMsg(String msg) {
        this.setMsg(msg);
        groupChatMediator.distributeMsg(this);
    }

    @Override
    void receiveMsg(String msg) {
        System.out.println(this.getName() + "接收:" + msg);
    }
}

/**
 * 聊天室中介接口
 *
 * @author lipangpang
 * @date 2021/12/27
 * @description
 */
public interface IGroupChatMediator {
    /**
     * 加入聊天室
     *
     * @param colleague
     */
    void join(IColleague colleague);

    /**
     * 分发群消息
     *
     * @param colleague
     */
    void distributeMsg(IColleague colleague);
}

/**
 * 聊天室中介
 *
 * @author lipangpang
 * @date 2021/12/27
 * @description
 */
public class GroupChatMediator implements IGroupChatMediator {
    private List colleagues = new ArrayList<>();

    @Override
    public void join(IColleague colleague) {
        colleagues.add(colleague);
    }

    @Override
    public void distributeMsg(IColleague colleague) {
        for (IColleague iColleague : colleagues) {
            if (iColleague == colleague) {
                continue;
            }
            iColleague.receiveMsg("[" + colleague.getName() + "]" + colleague.getMsg());
        }
    }
}

public class TestMain {
    public static void main(String[] args) {
        IGroupChatMediator groupChatMediator = new GroupChatMediator();
        IColleague zhangsan = new Colleague(groupChatMediator, "张三");
        IColleague lisi = new Colleague(groupChatMediator, "李四");
        IColleague wangwu = new Colleague(groupChatMediator, "王五");
        groupChatMediator.join(zhangsan);
        groupChatMediator.join(lisi);
        groupChatMediator.join(wangwu);
        zhangsan.sendMsg("你好啊");
        System.out.println("------------------");
        lisi.sendMsg("新年快乐");
        System.out.println("------------------");
        wangwu.sendMsg("happy new year");
    }
}

结果:

李四接收:[张三]你好啊
王五接收:[张三]你好啊
------------------
张三接收:[李四]新年快乐
王五接收:[李四]新年快乐
------------------
张三接收:[王五]happy new year
李四接收:[王五]happy new year

类图:

手把手教你23种设计模式_第33张图片

解释器模式

含义:给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。

解释器模式结构如下。

  1. 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。
  2. 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符

    都有一个具体终结表达式与之相对应。

  3. 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
  4. 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可

    以从这里获取这些值。

  5. 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,

    当然也可以通过环境角色间接访问解释器的解释方法。

示例:实现1+1=2,2-1=1的数学表达式运算。1,2数字是终结符角色,+,-运算符是非终结符角色。

/**
 * 表达式接口
 *
 * @author lipangpang
 * @date 2021/12/28
 * @description
 */
public interface IExpression {
    /**
     * 解释表达式
     *
     * @return
     */
    Integer interpreter();
}

/**
 * 终结符表达式
 *
 * @author lipangpang
 * @date 2021/12/28
 * @description
 */
public class TerminalExpression implements IExpression {
    /**
     * 当前终结符存储的值
     */
    private Integer value;

    public TerminalExpression(Integer value) {
        this.value = value;
    }

    @Override
    public Integer interpreter() {
        return this.value;
    }
}

/**
 * 非终结符表达式
 *
 * @author lipangpang
 * @date 2021/12/28
 * @description
 */
public abstract class NonTerminalExpression implements IExpression {
    /**
     * 终结符表达式左值
     */
    protected IExpression leftValue;
    /**
     * 终结符表达式右值
     */
    protected IExpression rightValue;

    public NonTerminalExpression(IExpression leftValue, IExpression rightValue) {
        this.leftValue = leftValue;
        this.rightValue = rightValue;
    }

}

/**
 * 加运算非终结符
 *
 * @author lipangpang
 * @date 2021/12/28
 * @description
 */
public class AddExpression extends NonTerminalExpression {
    public AddExpression(IExpression leftValue, IExpression rightValue) {
        super(leftValue, rightValue);
    }

    @Override
    public Integer interpreter() {
        return this.leftValue.interpreter() + this.rightValue.interpreter();
    }
}

/**
 * 减运算非终结符
 *
 * @author lipangpang
 * @date 2021/12/28
 * @description
 */
public class SubExpression extends NonTerminalExpression {
    public SubExpression(IExpression leftValue, IExpression rightValue) {
        super(leftValue, rightValue);
    }

    @Override
    public Integer interpreter() {
        return this.leftValue.interpreter() - this.rightValue.interpreter();
    }
}

/**
 * 计算器环境类
 *
 * @author lipangpang
 * @date 2021/12/29
 * @description
 */
public class CalculatorContext {

    public Integer parse(String info) {
        String[] split = info.split(" ");
        IExpression leftValue = null;//运算左值
        IExpression rightValue = null;//运算右值
        IExpression operator = null;//运算符
        for (String element : split) {
            if (!("+".equals(element) || "-".equals(element))) {
                if (leftValue == null) {
                    leftValue = new TerminalExpression(Integer.parseInt(element));
                    continue;
                }
                if (rightValue == null) {
                    rightValue = new TerminalExpression(Integer.parseInt(element));
                }
            }
        }
        for (String element : split) {
            if ("+".equals(element)) {
                operator = new AddExpression(leftValue, rightValue);
            } else if ("-".equals(element)) {
                operator = new SubExpression(leftValue, rightValue);
            }
        }
        return operator.interpreter();
    }
}

public class TestMain {
    public static void main(String[] args) {
        System.out.println(new CalculatorContext().parse("1 + 1"));
        System.out.println(new CalculatorContext().parse("2 - 1"));
    }
}

结果:

2
1

类图:

手把手教你23种设计模式_第34张图片

访问者模式

含义:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新

的操作,为数据结构中的每个元素提供多种访问方式。

访问者模式结构如下。

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

    了被访问的具体元素。

  2. 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
  3. 抽象元素(Element)角色:声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
  4. 具体元素(ConcreteElement)角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素

    中可能还包含本身业务逻辑的相关操作。

  5. 对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、

    Set、Map 等聚合类实现。

示例:厨师会把面粉做成面条,烘培师会把面粉做成面包;厨师会把鸡蛋做成煎蛋,烘培师会把鸡蛋做成蛋糕。

/**
 * 原料接口
 *
 * @author lipangpang
 * @date 2021/12/29
 * @description
 */
public interface IMaterial {
    String accept(IPersonVisitor personVisitor);
}

/**
 * 面粉
 *
 * @author lipangpang
 * @date 2021/12/29
 * @description
 */
public class Flour implements IMaterial {
    @Override
    public String accept(IPersonVisitor personVisitor) {
        return personVisitor.create(this);
    }
}

/**
 * 鸡蛋
 *
 * @author lipangpang
 * @date 2021/12/29
 * @description
 */
public class Egg implements IMaterial {
    @Override
    public String accept(IPersonVisitor personVisitor) {
        return personVisitor.create(this);
    }
}

/**
 * 人访问者接口
 *
 * @author lipangpang
 * @date 2021/12/29
 * @description
 */
public interface IPersonVisitor {
    String create(Flour flour);

    String create(Egg egg);
}

/**
 * 烘培师
 *
 * @author lipangpang
 * @date 2021/12/29
 * @description
 */
public class Baker implements IPersonVisitor {
    @Override
    public String create(Flour flour) {
        return "烘培师把面粉做成面包";
    }

    @Override
    public String create(Egg egg) {
        return "烘培师把鸡蛋做成蛋糕";
    }
}

/**
 * 厨师
 *
 * @author lipangpang
 * @date 2021/12/29
 * @description
 */
public class Cook implements IPersonVisitor {
    @Override
    public String create(Flour flour) {
        return "厨师把面粉做成面条";
    }

    @Override
    public String create(Egg egg) {
        return "厨师把鸡蛋做成煎蛋";
    }
}

/**
 * 材料容器
 *
 * @author lipangpang
 * @date 2021/12/29
 * @description
 */
public class MaterialContainer {
    List materials = new ArrayList<>();

    public void addMaterial(IMaterial material) {
        materials.add(material);
    }

    public void accept(IPersonVisitor personVisitor) {
        for (IMaterial material : materials) {
            String result = material.accept(personVisitor);
            System.out.println(result);
        }
    }
}

public class TestMain {
    public static void main(String[] args) {
        MaterialContainer materialContainer = new MaterialContainer();
        materialContainer.addMaterial(new Flour());
        materialContainer.addMaterial(new Egg());
        materialContainer.accept(new Cook());
        System.out.println("------------");
        materialContainer.accept(new Baker());
    }
}

结果:

厨师把面粉做成面条
厨师把鸡蛋做成煎蛋
------------
烘培师把面粉做成面包
烘培师把鸡蛋做成蛋糕

类图:

手把手教你23种设计模式_第35张图片

观察者模式

含义:多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

观察者模式结构如下。

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

    知所有观察者的抽象方法。

  2. 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所

    有注册过的观察者对象。

  3. 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
  4. 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

示例:微信公众号发布新消息时,所有关注者都会接受到信息提醒。

/**
 * 用户观察者接口
 *
 * @author lipangpang
 * @date 2021/12/30
 * @description
 */
public interface IUserObserver {
    /**
     * 接受消息
     *
     * @param msg
     */
    void receive(String msg);
}

/**
 * @author lipangpang
 * @date 2021/12/30
 * @description
 */
public class UserObserver implements IUserObserver {
    /**
     * 观察者姓名
     */
    private String name;

    public UserObserver(String name) {
        this.name = name;
    }

    @Override
    public void receive(String msg) {
        System.out.println(this.name + "接收消息:" + msg);
    }
}

/**
 * 公众号主题抽象类
 *
 * @author lipangpang
 * @date 2021/12/30
 * @description
 */
public abstract class IOfficialAccountSubject {
    /**
     * 所有订阅公众号的用户观察者
     */
    List userObservers = new ArrayList<>();

    /**
     * 订阅公众号
     *
     * @param userObserver
     */
    public void addObserver(IUserObserver userObserver) {
        userObservers.add(userObserver);
    }

    /**
     * 推送消息
     *
     * @param msg
     */
    public abstract void notifyObserver(String msg);
}

/**
 * 公众号
 *
 * @author lipangpang
 * @date 2021/12/30
 * @description
 */
public class OfficialAccountSubject extends IOfficialAccountSubject {
    @Override
    public void notifyObserver(String msg) {
        System.out.println("公众号推送消息:" + msg);
        System.out.println("----------------");
        for (IUserObserver userObserver : userObservers) {
            userObserver.receive(msg);
        }
    }
}

public class TestMain {
    public static void main(String[] args) {
        IOfficialAccountSubject officialAccountSubject = new OfficialAccountSubject();
        UserObserver zhangsan = new UserObserver("zhangsan");
        UserObserver lisi = new UserObserver("lisi");
        officialAccountSubject.addObserver(zhangsan);
        officialAccountSubject.addObserver(lisi);
        officialAccountSubject.notifyObserver("新年快乐");
        System.out.println();
        officialAccountSubject.notifyObserver("给大伙派送红包");
    }
}

结果:

公众号推送消息:新年快乐
----------------
zhangsan接收消息:新年快乐
lisi接收消息:新年快乐

公众号推送消息:给大伙派送红包
----------------
zhangsan接收消息:给大伙派送红包
lisi接收消息:给大伙派送红包

类图:

手把手教你23种设计模式_第36张图片

委派模式(不属于GoF 23 种设计模式)

含义:负责任务的调度和分配任务。

示例:实现servlet的请求,根据不同的用户请求url调用不同的方法。

/**
 * 商品控制器
 *
 * @author lipangpang
 * @date 2021/12/30
 * @description
 */
public class ProductController {
    public void getProductInfo() {
        System.out.println("这是商品信息");
    }
}

/**
 * 用户控制器
 *
 * @author lipangpang
 * @date 2021/12/30
 * @description
 */
public class UserController {
    public void getUserInfo() {
        System.out.println("这是用户信息");
    }
}

/**
 * servlet接口
 *
 * @author lipangpang
 * @date 2021/12/30
 * @description
 */
public interface IServlet {
    Object dispatcher(String url);
}

/**
 * servlet
 *
 * @author lipangpang
 * @date 2021/12/30
 * @description
 */
public class Servlet implements IServlet {

    @Override
    public Object dispatcher(String url) {
        if ("/user".equals(url)) {
            new UserController().getUserInfo();
        } else if ("/product".equals(url)) {
            new ProductController().getProductInfo();
        }
        return null;
    }
}


/**
 * 客户端
 *
 * @author lipangpang
 * @date 2021/12/30
 * @description
 */
public class Client {
    private IServlet servlet;

    public Client(IServlet servlet) {
        this.servlet = servlet;
    }

    public void sendCommand(String url) {
        this.servlet.dispatcher(url);
    }
}

public class TestMain {
    public static void main(String[] args) {
        Servlet servlet = new Servlet();
        Client client = new Client(servlet);
        client.sendCommand("/user");
        client.sendCommand("/product");
    }
}

结果:

这是用户信息
这是商品信息

类图:

手把手教你23种设计模式_第37张图片