java—01 设计模式&设计原则(I)

目录

一、设计模式

1. 单一职责原则

2. 里氏替换原则

3. 依赖倒置原则

4. 接口隔离原则ISP

5. 迪米特法则(最少知识原则)

6. 开闭原则

二、设计原则

(一)、创建型模式

1. 单例 Singleton

2. 原型 Prototype

3. 工厂方法 FactoryMethod

4. 抽象工厂 AbstractFacory

5. 建造者 / 生成器模式 Builder

(二)结构型模式

6. 代理 Proxy

7. 适配器 Adapter

8. 桥接 Bridge

9. 装饰 Decorator

10. 门面 Facade

11. 享元 / 蝇量 Flyweight 

12. 组合 Composite

(三)、行为型模式

13. 模版方法 Template Method  ※※※※※

14. 策略 Strategy ※※※※※

15. 命令 Command ※※※※※

16. 职责链 Chain of Reponsibility ※※※

17. 状态 State ※※※

状态机 ※※※※※

18. 观察者 Observer ※※※※※

19. 中介者 Mediator ※※※※

20. 迭代器 Iterator 

21. 访问者 Visitor ※

22. 备忘录 Memento ※

23. 解释器 Interpreter 


研发 --> 架构  (定义、例子,框架或接口中用过相关的开发)

一、设计原则

1. 单一职责原则

Single Reposibility Principle

定义:一个类或者模块/服务/架构只负责完成一个职责。例如服务拆成微服务。

例如:电商项目拆分成支付模块、库存模块、订单模块、物流模块……

存在的必要性:当系统某一部分出现问题,可以以模块为单位进行替换。(高内聚、低耦合)

2. 里氏替换原则

LSP:Liskov Substitution Principle

定义:多用组合,少用继承。(组合:在自己的类里引用其他的类(new那个类))

重用父类方法或者说的借用父类能力时候,用继承;定制化的行为最好用组合。

含义:(1)里氏替换原则是针对继承而言的,如果继承是为了实现代码重用,也就是为了共享方法,那么共享的父类方法就应该保持不变,不能被子类重新定义。子类只能通过新添加方法来扩展功能,父类和子类都可以实例化,而子类继承的方法和父类是一样的,父类调用方法的地方,子类也可以调用同一个继承得来的,逻辑和父类一致的方法,这时用子类对象将父类对象替换掉时,当然逻辑一致,相安无事。(2)如果继承的目的是为了多态,而多态的前提就是子类覆盖并重新定义父类的方法,为了符合LSP,我们应该将父类定义为抽象类,并定义抽象方法,让子类重新定义这些方法,当父类是抽象类时,父类就是不能实例化,所以也不存在可实例化的父类对象在程序里。也就不存在子类替换父类示例(根本不存在父类示例了)时逻辑不一致的可能。

3. 依赖倒置原则

DIP:Dependence Inversion Principle

定义:下层模块引入上层模块的依赖,改变原有自上而下的依赖方向。

针对接口编程,而非根据对象编程。

adapter层分为SDK和web,controller依赖web,订单、库存、物流等服务在domain层,adapter层依赖APP层,APP层依赖Domain层,infrastructure层反方向依赖domain层(依赖倒置),基础设施层:各种数据库、rpc调用、缓存等,反向依赖的原因:假如domain层的订单服务,需要OrderDao的接口,包含:order,search,delete等方法,操作的时候针对接口编程,domain层调用的是OrderDao的接口的order方法,在domain层只能看到OrderDao.order()方法,order()方法的具体实现在基础设施层,在该层调用MySqlOrderDao,实现order,search,delete等方法,当数据量大了,需要分库分表,引入NoSql(HBase、MongoDB),特点:高弹性,不存在分库分表。此时将MySqlOrderDao接口替换为NoSqlOrderDao接口,在domain层看到的只有OrderDao.order(),而不会看到OrderDao的具体实现。

 DDD:Domain Driver Design 根据领域划分的领域驱动设计

4. 接口隔离原则ISP

ISP:Interface Segregation Principle

定义:建立单一接口,不要建立臃肿庞大的接口。接口尽量细化,同时接口中的方法尽量少。

含义:

(1)接口要尽量小:不要违反单一职责原则;要适度的小;

(2)接口要高内聚:提高接口、类、模块的处理能力,减少对外的交互;

(3)定制服务:通过对高质量接口的组装,实现服务的定制化(多组合少继承)

5. 迪米特法则(最少知识原则)

LoD:Law of Demeter

定义:只和密友谈话

解释:一个类应该对自己需要耦合或者调用的类知道得最少,你(被耦合或者被调用的类)的内部是如何复杂,那是你的事儿,和我没关系,我就知道你提供的这么多public方法,我就调用这么多,其他的我一概不知。

6. 开闭原则

定义:类、方法、模块应该对扩展开放,对修改关闭

含义:添加一个功能应该是在已有的代码基础上进行扩展,而不是修改已有的代码。

二、设计模式

(一)、创建型模式

创建型模式的主要关注点是:“怎样创建对象”,它的主要特点是:“将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。

1. 单例 Singleton

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

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

注意:涉及到创建构造器时,构造器都是private的。

五种实现方式:(面)(前三种能写出来)②

(1)饿汉式:线程安全,调用效率高,但是不能延时加载(常用)

延时加载:使用方法的时候才创建对象。

无论用不用,加载进来的时候就会创建一个实例,用到的时候返回该实例即可。

/**
 * @description 饿汉式(线程安全,调用效率高,但是不能延时加载)
 **/
public class SingletonDemo1 {

    private static SingletonDemo1 instance = new SingletonDemo1();

    private SingletonDemo1(){}

    public static SingletonDemo1 getInstance(){
        return instance;
    }
}

(2)懒汉式:线程安全,调用效率不高,但是能延时加载

类初始化时不创建对象(延时加载),真正用的时候再创建,需要写一个创建的方法。

public class SingletonDemo2 {
    //类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)
    private static SingletonDemo2 instance;

    //构造器私有化
    private SingletonDemo2(){}

    //方法同步,调用效率低
    public static synchronized SingletonDemo2 getInstance(){
        if(instance == null) {
            instance = new SingletonDemo2();
        }
        return instance;
    }
}

因为方法上加了synchronized,所有的对象都会阻塞在该方法处,需要一个个按序串行调用,解决该问题需要双重校验。

(3)双重校验

在懒汉式的基础上进行了双重校验的优化。

public class SingletonDemo3 {

    private volatile static SingletonDemo3 singletonDemo3;

    private SingletonDemo3() {}

    public static SingletonDemo3 newInstance() {
        if (singletonDemo3 == null) {
            synchronized (SingletonDemo3.class) {
                if (singletonDemo3 == null) {
                    singletonDemo3 = new SingletonDemo3();
                }
            }
        }
        return singletonDemo3;
    }
}

当有多个对象调用newInstance方法时,由于没有synchronized,快的几个对象都会进入该方法,到达锁处,其中最快的对象会再判断是否为空,如果为空则创建对象,然后返回,剩下几个同一批次进来的在锁之后判断不为空则直接返回,比这几个对象慢的其他对象进入方法后判断对象不为空,直接返回。

(4)静态内部类:线程安全,调用效率高,可以延时加载(较常用)

使用内部类的方式创建了实例。

/**
 * 问题:问什么这种内部静态类的方式,是线程安全的?
 * 答:首先要了解类加载过程中的最后一个阶段:即类的初始化,类的初始化阶本质就是执行类构造器的<clinit>方法。那么什么是<clinit>方法?
 * 这不是由程序员写的程序,而是根据代码由javac编译器生成的。它是由类里面所有的【静态成员的的赋值语句】和【静态代码块】组成的。JVM内部会保证一个类的
 * <clinit>方法在多线程环境下被正确的加锁同步,也就是说如果多个线程同时去进行“类的初始化”,那么只有一个线程会去执行类的<clinit>方法,其他的线程
 * 都要阻塞等待,直到这个线程执行完<clinit>方法。然后执行完<clinit>方法后,其他线程唤醒,但是不会再进入<clinit>方法。也就是说同一个加载器下,
 * 一个类型只会初始化一次。
 *
 * 那么回到这个代码中,这里的静态变量的赋值操作进行编译之后实际上就是一个<clinit>代码,当我们执行getInstance方法的时候,会导致SingletonClassInstance
 * 类的加载,类加载的最后会执行类的初始化,但是即使在多线程情况下,这个类的初始化的<clinit>代码也只会被执行一次,所以他只会有一个实例。
 *
 * @description 静态内部类(线程安全,调用效率高,可以延时加载)
 * @author: muse
 **/
public class SingletonDemo4 {

    private SingletonDemo4(){
        System.out.println("SingletonDemo4");
    }

    /** 静态内部类 */
    private static class SingletonClassInstance {
        private static final SingletonDemo4 instance = new SingletonDemo4();
    }

    /** 只有在第一次调用时,才会被创建,可以认为是懒加载的升级版本 */
    public static SingletonDemo4 getInstance(){
        return SingletonClassInstance.instance;
    }

    public static void main(String[] args) {
        System.out.println("args = " + Arrays.deepToString(args));
        SingletonDemo4.getInstance();
        SingletonDemo4.getInstance();
    }
}

(5)枚举类(不常用)

public enum SingletonDemo5 {

    // 枚举元素本身就是单例
    INSTANCE;

    // 添加自己需要的操作,直接通过SingletonDemo5.INSTANCE.doSomething()的方式调用即可。方便、简洁又安全。
    public void doSomething() {
        System.out.println("doSomething");
    }
}

class Test {
    public static void main(String[] args) {
        SingletonDemo5.INSTANCE.doSomething();
    }
}

单例可以被破坏③

(1)反射获得对应的构造函数,可以setAccessible=true破坏掉private,进而创建破坏单例的对象。

(2)通过反序列化Serializable(RPC中常见)

2. 原型 Prototype

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

定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。也就是说,这种不通过new关键字来产生一个对象,而是通过对象复制(Java中的clone或者反序列化)来实现的模式,叫做原型模式。(克隆不走构造函数)

性能:原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环内产生大量的对象时,原型模式可能更好地体现其优点。

逃避构造函数的约束,直接在内存中拷贝,构造函数式不会执行的克隆不走构造函数①

/**
 * 通过clone方法创建的Prototype对象不会执行构造方法
 */
public class Prototype implements Cloneable {
    public static void main(String[] args) {
        System.out.println("【步骤1】开始执行Prototype类型的对象创建工作");
        Prototype prototype = new Prototype();

        /** 执行clone方法创建的Prototype对象 */
        System.out.println("【步骤2】开始执行clone操作");
        prototype.clone();
    }

    public Prototype() {
        System.out.println("-----Prototype的构造方法被执行了!-----");
    }

    @Override
    protected Prototype clone() {
        try {
            return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}

执行结果:可以看到在克隆的时候没有执行构造方法。

深拷贝与浅拷贝②:(面)基础数据类型,直接克隆,包括集合要深拷贝

/**
 * 浅拷贝&深拷贝
 */
@Data
public class Prototype1 implements Cloneable {
    private String name;
    private List<String> arrayList = new ArrayList<>();

    public static void main(String[] args) {
        Prototype1 prototype1 = new Prototype1();
        prototype1.setName("original object");
        prototype1.setValue("original object");

        Prototype1 clonePrototype1 = prototype1.clone();
        clonePrototype1.setName("clone object");
        /** 发现添加了执行了clone对象的setValue之后,也修改了prototype1中的arrayList中数据 */
        clonePrototype1.setValue("clone object");
        System.out.println(prototype1);
        System.out.println(clonePrototype1);
    }

    public void setValue(String value) {
        this.arrayList.add(value);
    }

    public List<String> getValue() {
        return this.arrayList;
    }

    /**
     * 浅拷贝
     * @return
     */
//    @Override
//    protected Prototype1 clone() {
//        try {
//            return (Prototype1)super.clone();
//        } catch (CloneNotSupportedException e) {
//            e.printStackTrace();
//        }
//        return null;
//    }

    /**
     * 深拷贝
     * @return
     */
    @Override
    protected Prototype1 clone() {
        Prototype1 prototype1 = null;
        try {
            prototype1 = (Prototype1)super.clone();
            prototype1.setArrayList(new ArrayList<>());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return prototype1;
    }

}

浅拷贝的运行结果:基本类型拷贝后不改变原值,集合拷贝后,将原值改为新值。

深拷贝的运行结果:(深拷贝重新创建了一个arrayList,跟原来的arrayList没关系了。另外基础类型和String类型不需要深度拷贝,对象和容器会需要深度拷贝。)

使用场景③

(1)类的初始化需要消耗非常多的资源。

(2)通过new产生一个对象需要非常繁琐的数据准备或访问。

(3)一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时。

3. 工厂方法 FactoryMethod

定义一个用于创建产品的接口,由子类决定生产什么产品。

(简单工厂 Simple Factory:不是设计模式,更像是一种编程习惯。用得多)

定义:定义了一个创建对象的接口(类或接口中的方法),但由子类决定要实例化的类 是哪一个。工厂方法把实例化推迟(下移)到子类。

简单工厂:

/**
 * 简单工厂
 */
private static void pizzaStoreV1Test() {
	PizzaStoreV1 pizzaStore = new PizzaStoreV1(new SimplePizzaFactory());
	pizzaStore.orderPizza("cheese");
}
public class PizzaStoreV1 {

    private SimplePizzaFactory factory;

    public PizzaStoreV1(SimplePizzaFactory factory) {
        this.factory = factory;
    }

    public Pizza orderPizza(String pizzaType) {
        Pizza pizza = factory.createPizza(pizzaType);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}
public class SimplePizzaFactory {
    public Pizza createPizza(String pizzaType) {
        Pizza pizza = null;
        if (pizzaType.equals("cheese")) {
            pizza = new CheesePizza();
        } else if (pizzaType.equals("pepperoni")) {
            pizza = new PepperoniPizza();
        } else if (pizzaType.equals("clam")) {
            pizza = new ClamPizza();
        } else if (pizzaType.equals("veggie")) {
            pizza = new VeggiePizza();
        }
        return pizza;
    }
}

工厂方法:

/**
 * 工厂方法
 */
private static void pizzaStoreV2Test() {
	PizzaStoreV2 pizzaStore = new com.muse.patterns.factory.store.v2.ChicagoPizzaStore(); // 选择纽约地区的披萨店
	pizzaStore.orderPizza("cheese");
}
public abstract class PizzaStoreV2 {

    protected abstract Pizza createPizza(String pizzaType);

    public Pizza orderPizza(String pizzaType) {
        Pizza pizza = createPizza(pizzaType);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}
public class ChicagoPizzaStore extends PizzaStoreV2 {

    protected Pizza createPizza(String pizzaType) {
        Pizza pizza = null;
        if (pizzaType.equals("cheese")) {
            pizza = new ChicagoCheesePizza();
        } else if (pizzaType.equals("pepperoni")) {
            pizza = new ChicagoPepperoniPizza();
        } else if (pizzaType.equals("clam")) {
            pizza = new ChicagoClamPizza();
        } else if (pizzaType.equals("veggie")) {
            pizza = new ChicagoVeggiePizza();
        }
        return pizza;
    }
}

4. 抽象工厂 AbstractFacory

提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。(用得少)

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

工厂方法: 通过抽象方法提供对象生成入口。(继承)

抽象工厂: 通过接口,来创建一组产品。(组合)

/**
 * 抽象工厂
 */
private static void pizzaStoreV3Test() {
	PizzaStoreV3 pizzaStore = new com.muse.patterns.factory.store.v3.NYPizzaStore();
	pizzaStore.orderPizza("cheese");
}
public class NYPizzaStore extends PizzaStoreV3 {

    protected Pizza createPizza(String pizzaType) {
        Pizza pizza = null;
        PizzaIngredientFactory pizzaIngredientFactory = new NYPizzaingredientFactory(); // 纽约口味配料工厂
        if (pizzaType.equals("cheese")) {
            pizza = new CheesePizza(pizzaIngredientFactory);
        } else if (pizzaType.equals("pepperoni")) {
            pizza = new PepperoniPizza(pizzaIngredientFactory);
        } else if (pizzaType.equals("clam")) {
            pizza = new ClamPizza(pizzaIngredientFactory);
        } else if (pizzaType.equals("veggie")) {
            pizza = new VeggiePizza(pizzaIngredientFactory);
        }
        return pizza;
    }
}
public abstract class PizzaStoreV3 {

    /** 创建pizza下移到子类中去实现 */
    protected abstract Pizza createPizza(String pizzaType);

    /** 创建披萨的过程是固定的,所以在抽象类中实现 */
    public Pizza orderPizza(String pizzaType) {
        Pizza pizza = createPizza(pizzaType);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

/**
 * @description 纽约原料工厂
 * @author: muse
 **/
public class NYPizzaingredientFactory implements PizzaIngredientFactory {

    // 厚的面包皮生面团
    public Dough createDough() {
        return new ThickCrustDough();
    }

    // 梅子西红柿酱汁
    public Sauce createSauce() {
        return new PlumTomatoSauce();
    }

    // 莫泽雷勒干酪
    public Cheese createCheese() {
        return new MozzarellaCheese();
    }

    // 冷冻蛤蜊
    public Clams createClams() {
        return new FrozenClams();
    }

    @Override
    public String toString() {
        return "NYPizzaingredientFactory";
    }
}
/**
 * @description 披萨原料工厂
 * @author: muse
 **/
public interface PizzaIngredientFactory {

    // 获得生面团原料
    Dough createDough();

    // 获得酱汁原料
    Sauce createSauce();

    // 获得奶酪原料
    Cheese createCheese();

    // 获得蛤蜊原料
    Clams createClams();
}
/**
 * @description 奶酪口味披萨
 * @author: muse
 **/
public class CheesePizza extends Pizza {

    public CheesePizza(PizzaIngredientFactory pizzaIngredientFactory) {
        this.pizzaIngredientFactory = pizzaIngredientFactory;
        this.name = "CheesePizza";
    }

    /** 奶酪披萨需要原料:面团、酱、干酪 */
    public void prepare() {
        System.out.println("CheesePizza prepare() include: dough、sauce、cheese");
        dough = pizzaIngredientFactory.createDough();
        sauce = pizzaIngredientFactory.createSauce();
        cheese = pizzaIngredientFactory.createCheese();
    }
}
/**
 * @description 披萨抽象类
 * @author: muse
 **/
public abstract class Pizza {
    protected String name;
    protected Dough dough; // 面团
    protected Sauce sauce; // 酱
    protected Cheese cheese; // 干酪
    protected Clams clams; // 蛤蜊
    protected PizzaIngredientFactory pizzaIngredientFactory; // 披萨原料抽象工厂

    /** 准备原材料 */
    public abstract void prepare();

    public void bake() {
        System.out.println(name + " and " + pizzaIngredientFactory +" bake()");
    }

    public void cut() {
        System.out.println(name + " and " + pizzaIngredientFactory + " cut()");
    }

    public void box() {
        System.out.println(name + " and " + pizzaIngredientFactory + " box()");
    }
}

/**
 * @description 披萨商店v3版本
 * @author: muse
 **/
public abstract class PizzaStoreV3 {

    /** 创建pizza下移到子类中去实现 */
    protected abstract Pizza createPizza(String pizzaType);

    /** 创建披萨的过程是固定的,所以在抽象类中实现 */
    public Pizza orderPizza(String pizzaType) {
        Pizza pizza = createPizza(pizzaType);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

5. 建造者 / 生成器模式 Builder

将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。

定义:使用生成器模式,可以封装一个产品的构造过程,并允许按步骤构造产品。

优点:

(1)将一个复杂对象的创建过程封装起来。

(2)允许对象通过多个步骤来创建,并且可以改变过程。

(3)向客户隐藏产品内部的表现。

(4)产品的实现可以被替换,因为客户只看到一个抽象接口。

用途: 经常被用来创建组合结构。

缺点:与工厂模式相比,采用生成器模式创建对象的客户,需要具备更多的领域知识

public interface Builder {

    // 安装引擎
    Builder initalEngine(String engine);

    // 安装齿轮
    Builder initalGear(String gear);

    // 安装车门
    Builder initalDoor(String door);

    // 安装轮胎
    Builder initailWheel(String wheel);

    // 获得构建后的汽车
    Car getCar();
}
public class AudiBuilder implements Builder {

    private Car car;

    public AudiBuilder() {
        car = new Car("Audi普通的发动机",
                "Audi普通标准的齿轮",
                "Audi普通标准的车门",
                "Audi普通标准的轮胎");
    }

    @Override
    public Builder initalEngine(String engine) {
        car.setEngine(engine);
        return this;
    }

    @Override
    public Builder initalGear(String gear) {
        car.setGear(gear);
        return this;
    }

    @Override
    public Builder initalDoor(String door) {
        car.setDoor(door);
        return this;
    }

    @Override
    public Builder initailWheel(String wheel) {
        car.setWheel(wheel);
        return this;
    }

    @Override
    public Car getCar() {
        return car;
    }
}
public class BMWBuilder implements Builder {

    private static Car car = new Car("BMW普通的发动机",
            "BMW普通标准的齿轮",
            "BMW普通标准的车门",
            "BMW普通标准的轮胎");

    @Override
    public Builder initalEngine(String engine) {
        car.setEngine(engine);
        return this;
    }

    @Override
    public Builder initalGear(String gear) {
        car.setGear(gear);
        return this;
    }

    @Override
    public Builder initalDoor(String door) {
        car.setDoor(door);
        return this;
    }

    @Override
    public Builder initailWheel(String wheel) {
        car.setWheel(wheel);
        return this;
    }

    @Override
    public Car getCar() {
        return car;
    }
}
@ToString
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Car {

    private String engine = "普通标准的发动机";

    private String gear = "普通标准的齿轮";

    private String door = "普通标准的车门";

    private String wheel = "普通标准的轮胎";
}
public class Worker {

    Car createA4LCar() {
        return new AudiBuilder().
                initalGear("6速双离合变速箱").
                initalDoor("A4L的门").
                initalEngine("Audi的4缸发动机").
                getCar();
    }

    Car createR8Car() {
        return new AudiBuilder().
                initalEngine("16缸跑车引擎").
                initalDoor("碳纤维轻量级车门").
                initalGear("7档湿式双离合变速箱").
                initailWheel("米其林Top2竞速级轮胎").
                getCar();
    }

    Car createCommonBMW() {
        return new BMWBuilder().getCar();
    }
}
public class BuilderTest {

    public static void main(String[] args) {
        Worker worker = new Worker();
        Car audiR8 = worker.createR8Car();
        Car audiA4L = worker.createA4LCar();
        Car commonBMW = worker.createCommonBMW();

        System.out.println("audiR8=" + audiR8);
        System.out.println("audiA4L=" + audiA4L);
        System.out.println("commonBMW=" + commonBMW);
    }
}

运行结果:

(二)结构型模式

结构型模式描述如何将类或对象按某种布局组成更大的结构。分为类结构型模式(采用 继承机制来组织接口和类)和对象结构型模式(釆用组合或聚合来组合对象)

6. 代理 Proxy

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

解决问题:当我们想要对一个业务类进行某些横切性的增强时,例如:增加请求与响应 的日志、增加权限校验、增加远程请求对象封装等等。我们可以采用代理模式去实现,而不需要修改原有的类。

定义:代理模式为另一个对象提供一个替身占位符,以控制对这个对象的访问。使用 代理模式创建代理对象,让代理对象控制某对象的访问,被代理的对象可以是远程的对 象、创建开销大的对象或需要安全控制的对象。

SpringAOP中采用的JDK动态代理,就是最典型的例子。

public interface Subject {
    void request();
}
public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("-----RealSubject 开始执行业务操作-----");
    }
}
public class Proxy implements Subject {

    // 被代理的对象
    private Subject subject;

    public Proxy(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void request() {
        beforeProcessor();
        subject.request();
        afterProcessor();
    }

    private void beforeProcessor() {
        System.out.println("-----Proxy before processor-----");
    }

    private void afterProcessor() {
        System.out.println("-----Proxy after processor-----");
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        // Subject subject = new RealSubject();
        Subject subject = new Proxy(new RealSubject());
        subject.request();
    }
}

运行结果:

补充……

7. 适配器 Adapter 

将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。

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

public interface Target {

    void prepare();

    void execute();
}
public class NormalTarget implements Target {
    public void prepare() {
        System.out.println("NormalTarget prepare()");
    }

    public void execute() {
        System.out.println("NormalTarget execute()");
    }
}

public class Adapter implements Target {
    // 待适配的类
    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    public void prepare() {
        adaptee.prepare1();
        adaptee.prepare2();
        adaptee.prepare3();
    }

    public void execute() {
        adaptee.doingSomething();
    }
}
public class Adaptee {
    public void prepare1() {
        System.out.println("Adaptee prepare1()");
    }
    public void prepare2() {
        System.out.println("Adaptee prepare2()");
    }
    public void prepare3() {
        System.out.println("Adaptee prepare3()");
    }
    public void doingSomething() {
        System.out.println("Adaptee doingSomething()");
    }
}
public class AdapterTest {
    public static void main(String[] args) {
        Client client = new Client();

        System.out.println("------------NormalTarget------------");
        client.setTarget(new NormalTarget());
        client.work();

        System.out.println("------------Adaptee------------");
        client.setTarget(new Adapter(new Adaptee())); // 适配器转换
        client.work();
    }
}

运行结果:

8. 桥接 Bridge

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

定义:将抽象部分和实现部分,分离解耦,使得两者可以独立地变化。桥接模式通过将实现和抽象放在两个不同的类层次中而使它们可以独立变化。

优点:

(1)将实现予以解耦,抽象和实现可以独立扩展,不会影响到对方。

(2)对于“具体的抽象类”所做的改变,不会影响到客户。

用途: 适合使用在需要跨越多个平台的图形和窗口系统上。 当需要用不同的方式改变接口和实现时,你会发现桥接模式很好用。

缺点:增加了复杂度。

/**
 * 颜色大类
 */
public interface ColorImplementor {

    String getColor();
}
/**
 * 蓝色墨水
 */
public class BlueColor implements ColorImplementor {
    @Override
    public String getColor() {
        return "Blue";
    }
}
/**
 * 红色墨水
 */
public class RedColor implements ColorImplementor {
    @Override
    public String getColor() {
        return "Red";
    }
}
/**
 * 抽象画笔类
 */
@Data
public abstract class BrushPenAbstraction {

    // 颜色接口(Has-A关系,桥接)
    protected ColorImplementor color;

    // 绘画操作
    public abstract void draw();

}
/**
 * 粗毛笔实现类
 */
public class BigBurshPen extends BrushPenAbstraction {
    @Override
    public void draw() {
        System.out.println("Big and " + color.getColor() + " drawing!");
    }
}
/**
 * 中毛笔实现类
 */
public class MiddleBurshPen extends BrushPenAbstraction {
    @Override
    public void draw() {
        System.out.println("Middle and " + color.getColor() + " drawing!");
    }
}
/**
 * 细毛笔实现类
 */
public class SmallBurshPen extends BrushPenAbstraction {
    @Override
    public void draw() {
        System.out.println("Small and " + color.getColor() + " drawing!");
    }
}
/**
 * 桥梁模式测试类
 */
public class BridgeTest {
    public static void main(String[] args) {
        BrushPenAbstraction brushPen = new BigBurshPen();
        brushPen.setColor(new RedColor());
        brushPen.draw();

        brushPen.setColor(new BlueColor());
        brushPen.draw();

        brushPen = new SmallBurshPen();
        brushPen.setColor(new BlueColor());
        brushPen.draw();
    }
}

运行结果:

9. 装饰 Decorator

会造成类爆炸。生产上的使用:过滤器、网关。

动态地给对象增加一些职责,即:增加其额外的功能。(附加+家族的概念)

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

/**
 * @description 食物抽象类
 * @author: muse
 **/
public abstract class Food {

    String description = "食物";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}
/**
 * @description 辅料抽象类
 * @author: muse
 **/
public abstract class AccessoriesDecorator extends Food {

    public abstract String getDescription();
}
/**
 * @description 鸡蛋
 * @author: muse
 **/
public class Egg extends AccessoriesDecorator {

    private Food food;

    public Egg(Food food) {
        this.food = food;
    }

    public String getDescription() {
        return "鸡蛋";
    }

    public double cost() {
        System.out.println("添加鸡蛋售价:" + 1 + "元");
        return 1 + food.cost();
    }
}
/**
 * @description 香肠
 * @author: muse
 **/
public class Sausage extends AccessoriesDecorator {
    private Food food;

    public Sausage(Food food) {
        this.food = food;
    }

    public String getDescription() {
        return "香肠";
    }

    public double cost() {
        System.out.println("添加香肠售价:" + 3 + "元");
        return 3 + food.cost();
    }
}
/**
 * @description 基础版煎饼果子
 * @author: muse
 **/
public class JianBing extends Food {

    public JianBing() {
        description = "基础版煎饼果子";
    }

    public double cost() {
        System.out.println("基础版煎饼果子售价:" + 7 + "元");
        return 7;
    }
}
public class DecoratorTest {
    public static void main(String[] args) {
        // 创建煎饼果子
        Food jianBing = new JianBing();
        // 创建鸡蛋,加入到煎饼果子中
        Food egg = new Egg(jianBing);
        // 创建香肠,加入到煎饼果子中
        Food sausage = new Sausage(egg);
        System.out.println("总金额为:" + sausage.cost() + "元");
    }
}

运行结果:

10. 门面 Facade

为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。(最小知识原则)

定义:提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

public class Car {
    private Engine engine;
    private Door door;
    private DashboardDisplay display;
    private Key key;

    public Car() {
        engine = new Engine();
        door = new Door();
        display = new DashboardDisplay();
        key = new Key();
    }

    /** 汽车启动 */
    public void start() {
        if (key.turns()) {
            door.lock();
            engine.start();
            display.refreshDisplay();
        }
    }
}
public class DashboardDisplay {
    void refreshDisplay() {
        System.out.println("DashboardDisplay refreshDisplay");
    }
}
public class Door {
    public void lock() {
        System.out.println("Door lock");
    }
}
public class Engine {
    public void start() {
        System.out.println("Engine start");
    }
}
public class Key {
    public boolean turns() {
        System.out.println("Key turns");
        return true;
    }
}
public class ClientTest {
    public static void main(String[] args) {
        Car car = new Car();
        car.start(); // 启动汽车,用户并不知道引擎、车门、钥匙、中控的运作
    }
}

运行结果:

11. 享元 / 蝇量 Flyweight 

运用共享技术来有效地支持大量细粒度对象的复用。 (非面)

定义:享元模式是池技术的重要实现方式,其定义如下:使用共享对象可以有效地支持 大量的细粒度的对象。

/**
 * 人员信息
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PersonInfo {

    // 姓名
    private String name;

    // 居住的详细地址
    private String address;

    // 核酸医院或网点唯一标识
    private Integer nucleicId;
}
/**
 * 核酸医院和网点信息信息
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class NucleicInfo {
    // 唯一标识
    private Integer id;

    // 核酸医院网点名称
    private String name;
}
/**
 * 核酸医院和网点信息客户端类
 */
public class NucleicInfoClient {
    // 存储核酸医院和网点的pool
    private HashMap<Integer, NucleicInfo> pool = Maps.newHashMap();

    // 构造函数中初始化池中数据
    public NucleicInfoClient() {
        NucleicInfo nucleicInfo;
        for (int i = 1; i <=10; i++) {
            nucleicInfo = new NucleicInfo(i, "北京市第"+i+"医院核酸网点");
            pool.put(nucleicInfo.getId(), nucleicInfo);
        }
    }

    public NucleicInfo getNucleicInfo(Integer key) {
        if (key == null || !pool.containsKey(key)) {
            return null;
        }
        return pool.get(key);
    }
}
/**
 * 蝇量模式测试类
 */
public class FlyweightTest {

    private static NucleicInfoClient client = new NucleicInfoClient();

    public static void main(String[] args) {
        PersonInfo bob = new PersonInfo("bob", "北京市海淀区xx大街xx小区x号楼x号", 2);
        PersonInfo muse = new PersonInfo("muse", "北京市朝阳区yy大街yy小区y号楼y号", 7);
        PersonInfo john = new PersonInfo("john", "上海市市徐汇区zz大街zz小区z号楼z号", 4);

        printPersonInfo(bob);
        printPersonInfo(muse);
        printPersonInfo(john);
    }

    public static void printPersonInfo(PersonInfo personInfo) {
        NucleicInfo nucleicInfo = client.getNucleicInfo(personInfo.getNucleicId());
        System.out.println(String.format("姓名=%s 居住地址=%s 核酸网点=%s", personInfo.getName(), personInfo.getAddress(),
                nucleicInfo.getName()));
    }
}

运行结果:

12. 组合 Composite

将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性(很少用)

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

/**
 * 职员类
 */
@AllArgsConstructor
public abstract class AbstractCorp {

    // 职员姓名
    private String name = "";

    // 职员的职位
    private String position = "";

    // 职员的薪水
    private int salary = 0;

    // 获得职员信息
    public String getCorpInfo() {
        return String.format("姓名:%s 职位:%s 薪水:%d", name, position, salary);
    }
}
/**
 * 管理层员工(即:非叶子节点职员)
 */
public class BranchCorp extends AbstractCorp {
    private ArrayList<AbstractCorp> corps = Lists.newArrayList();

    public BranchCorp(String name, String position, int salary) {
        super(name, position, salary);
    }

    // 添加职员
    public void addSubCorp(AbstractCorp... corp) {
        corps.addAll(Arrays.asList(corp));
    }

    // 返回手下的职员
    public ArrayList<AbstractCorp> getSubCorp() {
        return corps;
    }
}
/**
 * 基层员工(即:叶子节点职员)
 */
public class LeafCorp extends AbstractCorp {

    public LeafCorp(String name, String position, int salary) {
        super(name, position, salary);
    }
}
public class CompositeTest {
    public static void main(String[] args) {
        // 创建公司所有职员
        BranchCorp a = new BranchCorp("A", "董事长", 100000);
        BranchCorp b = new BranchCorp("B", "技术总监", 70000);
        BranchCorp c = new BranchCorp("C", "人事总监", 60000);
        BranchCorp d = new BranchCorp("D", "财务总监", 50000);
        LeafCorp b1 = new LeafCorp("B1", "程序员", 30000);
        LeafCorp b2 = new LeafCorp("B2", "程序员", 20000);
        LeafCorp c1 = new LeafCorp("C1", "HR", 15000);
        LeafCorp d1 = new LeafCorp("D1", "会计", 13000);

        // 根据下属关系,构建树形结构
        a.addSubCorp(b, c, d);
        b.addSubCorp(b1, b2);
        c.addSubCorp(c1);
        d.addSubCorp(d1);

        // 获得下属信息
        System.out.println("-----a的下属-----");
        getSubCorp(a);
        System.out.println("-----b的下属-----");
        getSubCorp(b);
    }

    // 获得branchCorp的下属
    private static void getSubCorp(BranchCorp branchCorp) {
        for (AbstractCorp corp : branchCorp.getSubCorp()) {
            System.out.println("corp = " + corp.getCorpInfo());
            if (corp instanceof BranchCorp) {
                getSubCorp((BranchCorp) corp);
            }
        }
    }
}

运行结果:

(三)、行为型模式

定义:行为型模式用于描述程序在运行时复杂的流程控制,即:描述多个类或对象之间 怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。

行为型模式分为类行为模式(采用继承机制来在类间分派行为)和对象行为模式(采用 组合或聚合在对象间分配行为)。由于组合关系或聚合关系比继承关系耦合度低,满足 “合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。

行为型模式是GoF设计模式中最为庞大的一类,它包含以下 11 种模式:

13. 模版方法 Template Method  ※※※※※

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

定义:在一个方法中定义一个算法骨架,而将一些步骤延迟到子类中。模板方法使得子类 可以在不改变算法结构的情况下,重新定义算法中的某些步骤

/**
 * @description 饮品制作类
 * @author: muse
 **/
public abstract class MakeBeverage {

    // 准备食谱(防止子类覆盖这个方法)
    final void prepareRecipe() {
        /** 第一步:把水煮沸 */
        boilWater();
        /** 第二步:酿造饮品 */
        brew();
        /** 第三步:把饮品倒入杯子中 */
        pourInCup();
        /** 第四步:往饮品中增加调味品 */
        addCondiments();
    }

    // 酿造
    abstract void brew();

    // 往饮品中增加调味品
    abstract void addCondiments();

    protected void boilWater() {
        System.out.println("把水煮沸");
    }

    private void pourInCup() {
        System.out.println("把饮品倒入杯子中");
    }
}
public class Coffee extends MakeBeverage {

    @Override
    protected void brew() {
        System.out.println("用沸水冲泡咖啡");
    }

    @Override
    protected void addCondiments() {
        System.out.println("往咖啡中添加糖和牛奶");
    }

}
public class Tea extends MakeBeverage {

    @Override
    protected void brew() {
        System.out.println("用沸水浸泡茶叶");
    }

    @Override
    protected void addCondiments() {
        System.out.println("往茶叶中添加柠檬");
    }
}
public class TemplateTest {
    public static void main(String[] args) {
        System.out.println("-----------开始冲泡茶叶-----------");
        Tea tea = new Tea();
        tea.prepareRecipe();

        System.out.println("-----------开始冲泡咖啡-----------");
        Coffee coffee = new Coffee();
        coffee.prepareRecipe();
    }
}

运行结果:

14. 策略 Strategy ※※※※※

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

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

/**
 * @description 鸭子抽象类
 * @author: muse
 **/
public abstract class Duck {

    protected FlyBehavior flyBehavior;

    protected QuackBehaviorBehavior quackBehaviorBehavior;

    public abstract void display();

    public void swin() {
        System.out.println("鸭子游泳");
    }

    public void performQuack() {
        quackBehaviorBehavior.quack();
    }

    public void performFly() {
        flyBehavior.fly();
    }

    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    public void setQuackBehaviorBehavior(QuackBehaviorBehavior quackBehaviorBehavior) {
        this.quackBehaviorBehavior = quackBehaviorBehavior;
    }
}
/**
 * @description 假鸭
 * @author: muse
 **/
public class DecoyDuck extends Duck {

    public DecoyDuck() {
        flyBehavior = new FlyNoWay(); // 不会飞
        quackBehaviorBehavior = new MuteQuack(); // 假鸭,不会叫
    }

    public void display() {
        System.out.println("假鸭的外貌特征");
    }
}
/**
 * @description 野鸭
 * @author: muse
 **/
public class MallardDuck extends Duck {

    public MallardDuck() {
        flyBehavior = new FlyWithWings(); // 鸭子飞行
        quackBehaviorBehavior = new Quack(); // 呱呱叫
    }

    public void display() {
        System.out.println("野鸭的外貌特征");
    }
}
/**
 * @description 红头鸭
 * @author: muse
 **/
public class RedheadDuck extends Duck {

    public RedheadDuck() {
        flyBehavior = new FlyWithWings(); // 鸭子飞行
        quackBehaviorBehavior = new Quack(); // 呱呱叫
    }

    public void display() {
        System.out.println("红头鸭的外貌特征");
    }
}
/**
 * @description 橡胶鸭
 * @author: muse
 **/
public class RubberDuck extends Duck {

    public RubberDuck() {
        flyBehavior = new FlyNoWay(); // 不会飞
        quackBehaviorBehavior = new Squeak(); // 吱吱叫
    }

    public void display() {
        System.out.println("橡胶鸭的外貌特征");
    }
}
/**
 * @description 飞行行为
 * @author: muse
 **/
public interface FlyBehavior {

    void fly();
}
/**
 * @description 不会飞行
 * @author: muse
 **/
public class FlyNoWay implements FlyBehavior {
    public void fly() {
        System.out.println("不会飞行");
    }
}
/**
 * @description 实现鸭子的飞行
 * @author: muse
 **/
public class FlyWithWings implements FlyBehavior {
    public void fly() {
        System.out.println("用翅膀飞行");
    }
}
/**
 * @description 叫声行为
 * @author: muse
 **/
public interface QuackBehaviorBehavior {

    void quack();
}
/**
 * @description 不会叫
 * @author: muse
 **/
public class MuteQuack implements QuackBehaviorBehavior {
    public void quack() {
        System.out.println("不会叫");
    }
}
/**
 * @description 呱呱叫
 * @author: muse
 **/
public class Quack implements QuackBehaviorBehavior {
    public void quack() {
        System.out.println("呱呱叫");
    }
}
/**
 * @description 吱吱叫
 * @author: muse
 **/
public class Squeak implements QuackBehaviorBehavior {
    public void quack() {
        System.out.println("吱吱叫");
    }
}
/**
 * @description 测试类
 * @author: muse
 **/
public class StrategyTest {
    public static void main(String[] args) {
        // 生成橡皮鸭
        Duck rubberDuck = new RubberDuck();
        rubberDuck.display();
        rubberDuck.performFly();
        System.out.println("-----------对橡皮鸭进行改造,让它能飞起来------------");
        rubberDuck.setFlyBehavior(new FlyWithWings()); // 更换会飞的算法族
        rubberDuck.performFly();
    }
}

运行结果:

15. 命令 Command ※※※※※

(使用消息中间件的时候)

将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开

定义:将“请求”封装命令对象,以便使用不同的请求、队列或日志来参数化其他对象。

在消息中间件常见。类似最小知识原则。

/**
 * @description 命令接口
 * @author: muse
 **/
public interface Command {
    void execute();
}
public class NoCommand implements Command {
    public void execute() {
        System.out.println("Doing nothing!");
    }
}

/**
 * @description
 * @author: muse
 **/
public class Light {

    /** 开灯操作 */
    public void on() {
        System.out.println("Light on!");
    }

    /** 关灯操作 */
    public void off() {
        System.out.println("Light off!");
    }
}
public class LightOffCommand implements Command {
    // 某品牌灯的控制接口
    private Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }

    public void execute() {
        light.off();
    }
}
public class LightOnCommand implements Command {
    // 某品牌灯的控制接口
    private Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    public void execute() {
        light.on();
    }
}
/**
 * @description 遥控器
 * @author: muse
 **/
public class RemoteController {
    private Command[] onCommands; // 开启开关集合
    private Command[] offCommands; // 关闭开关集合

    public RemoteController() {
        onCommands = new Command[8]; // 创建8个开启操作的按钮
        offCommands = new Command[8]; // 创建8个关闭操作的按钮

        for (int i = 0; i < 8; i++) {
            onCommands[i] = new NoCommand();
            offCommands[i] = new NoCommand();
        }
    }

    /** 往遥控器中添加命令 */
    public void addCommand(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }

    /** 按遥控器中某个开启键 */
    public void pushOnButton(int slot) {
        onCommands[slot].execute();
    }

    /** 按遥控器中某个关闭键 */
    public void pushOffButton(int slot) {
        offCommands[slot].execute();
    }
}
public class CommandTest {
    public static void main(String[] args) {
        Light light = new Light();
        RemoteController controller = new RemoteController();
        controller.addCommand(0, new LightOnCommand(light), new LightOffCommand(light));
        // 按下遥控器,第一排的ON按钮
        controller.pushOnButton(0);
        // 按下遥控器,第一排的OFF按钮
        controller.pushOffButton(0);
    }
}

运行结果:

16. 职责链 Chain of Reponsibility ※※※

把请求从链中的一个对象传到下一个对象,直到请 求被响应为止。通过这种方式去除对象之间的耦合。

定义: 当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式。 使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将 这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。(一般在配置中去设置)

网关场景,权限认证。

/**
 * 抽象处理类
 */
public abstract class AbstractProcessor {

    // 责任链中下一个处理节点
    private AbstractProcessor nextProcessor;

    // 返回的处理结果
    private String result;

    public final String handleMessage(List<Email> emails) {
        List<Email> filterEmails = emails.stream().
                filter(email -> email.getType() == this.emailType()).collect(Collectors.toList());
        result = this.execute(filterEmails);
        if (this.nextProcessor == null) return result;

        return this.nextProcessor.handleMessage(emails);
    }

    /** 设置责任链的下一个处理器 */
    public void setNextProcessor(AbstractProcessor processor) {
        this.nextProcessor = processor;
    }

    /** 获得当前Processor可以处理的邮件类型 */
    protected abstract int emailType();

    /** 具体处理邮件的方法 */
    protected abstract String execute(List<Email> emails);
}
/**
 * CEO处理类
 */
public class CeoProcessor extends AbstractProcessor {
    @Override
    protected int emailType() {
        return EmailType.FANS_EMAIL.type; // CEO负责处理粉丝邮件
    }

    @Override
    protected String execute(List<Email> emails) {
        if (CollectionUtils.isNotEmpty(emails)) {
            System.out.println("-------CEO开始处理邮件-------");
            emails.stream().forEach(email -> System.out.println(email.getContent()));
        }
        return "任务执行完毕!";
    }
}
/**
 * 业务部门处理类
 */
public class BusinessProcessor extends AbstractProcessor {

    @Override
    protected int emailType() {
        return EmailType.COOPERATE_EMAIL.type; // 业务部门负责处理商务合作邮件
    }

    @Override
    protected String execute(List<Email> emails) {
        if (CollectionUtils.isNotEmpty(emails)) {
            System.out.println("-------业务部门开始处理邮件-------");
            emails.stream().forEach(email -> System.out.println(email.getContent()));
        }
        return "任务执行完毕!";
    }
}
/**
 * 垃圾邮件处理类
 */
public class GarbageProcessor extends AbstractProcessor {

    @Override
    protected int emailType() {
        return EmailType.GARBAGE_EMAIL.type; // 垃圾处理器负责处理垃圾邮件
    }

    @Override
    protected String execute(List<Email> emails) {
        if (CollectionUtils.isNotEmpty(emails)) {
            System.out.println("-------垃圾开始处理邮件-------");
            emails.stream().forEach(email -> System.out.println(email.getContent()));
        }
        return "任务执行完毕!";
    }
}
/**
 * 法务部门处理类
 */
public class LawProcessor extends AbstractProcessor {

    @Override
    protected int emailType() {
        return EmailType.SLANDER_EMAIL.type; // 法务部门负责处理诽谤邮件
    }

    @Override
    protected String execute(List<Email> emails) {
        if (CollectionUtils.isNotEmpty(emails)) {
            System.out.println("-------法务部门开始处理邮件-------");
            emails.stream().forEach(email -> System.out.println(email.getContent()));
        }
        return "任务执行完毕!";
    }
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Email {
    private int type; // 邮件类型
    private String content; // 邮件内容
}
public enum EmailType {
    FANS_EMAIL(1, "粉丝邮件"),
    SLANDER_EMAIL(2, "诽谤邮件"),
    COOPERATE_EMAIL(3, "业务合作邮件"),
    GARBAGE_EMAIL(99, "垃圾邮件");

    public int type;
    public String remark;
    EmailType(int type, String remark) {
        this.type = type;
        this.remark = remark;
    }
}
/**
 * 责任链模式测试类
 */
public class ChainTest {

    // 初始化待处理邮件
    private static List<Email> emails = Lists.newArrayList(new Email(EmailType.FANS_EMAIL.type, "我是粉丝A"),
            new Email(EmailType.COOPERATE_EMAIL.type, "我要找你们合作"),
            new Email(EmailType.GARBAGE_EMAIL.type, "我是垃圾邮件"),
            new Email(EmailType.FANS_EMAIL.type, "我是粉丝B"));

    public static void main(String[] args) {
        // 初始化处理类
        AbstractProcessor ceoProcessor = new CeoProcessor();
        AbstractProcessor lawProcessor = new LawProcessor();
        AbstractProcessor businessProcessor = new BusinessProcessor();
        AbstractProcessor garbageProcessor = new GarbageProcessor();

        // 构建责任链
        ceoProcessor.setNextProcessor(lawProcessor);
        lawProcessor.setNextProcessor(businessProcessor);
        businessProcessor.setNextProcessor(garbageProcessor);

        // 开始处理邮件
        ceoProcessor.handleMessage(emails);
    }
}

运行结果:

17. 状态 State ※※※

状态机 ※※※※※

允许一个对象在其内部状态发生改变时改变其行为能力。

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

/**
 * 状态接口类
 */
public interface State {

    // 投入硬币操作
    void insertCoin();

    // 撤销投币操作
    void undoCoin();

    // 扭转曲柄操作
    void turnCrank();

    // 发放口香糖操作
    void dispense();
}
/**
 * 已经投放钱币状态类
 */
public class HasCoinState implements State {

    private GumballMachine gumballMachine;

    public HasCoinState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    @Override
    public void insertCoin() {
        System.out.println("您已经投入钱币!无须再次投入钱币!");
    }

    @Override
    public void undoCoin() {
        System.out.println("退款成功!");
        gumballMachine.setState(gumballMachine.getNoCoinState()); // 状态流转
    }

    @Override
    public void turnCrank() {
        System.out.println("正在出货中,请稍等");
        gumballMachine.setState(gumballMachine.getSoldState()); // 状态流转
    }

    @Override
    public void dispense() {
        System.out.println("你还没有扭转曲柄,口香糖不可以发放!");
    }
}
/**
 * 没有投放钱币状态类
 */
public class NoCoinState implements State {

    private GumballMachine gumballMachine; // 口香糖机

    public NoCoinState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    @Override
    public void insertCoin() {
        System.out.println("投入钱币成功!");
        gumballMachine.setState(gumballMachine.getHasCoinState()); // 状态流转
    }

    @Override
    public void undoCoin() {
        System.out.println("你还没有投入钱币,不能退回钱币!");
    }

    @Override
    public void turnCrank() {
        System.out.println("你还没有投入钱币,不能扭转曲柄!");
    }

    @Override
    public void dispense() {
        System.out.println("你还没有投入钱币,口香糖不可以发放!");
    }
}
/**
 * 口香糖售罄状态类
 */
public class SoldOutState implements State {

    private GumballMachine gumballMachine;

    public SoldOutState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    @Override
    public void insertCoin() {
        System.out.println("口香糖已经售罄。不能投入钱币");
    }

    @Override
    public void undoCoin() {
        System.out.println("退回钱币成功!");
    }

    @Override
    public void turnCrank() {
        System.out.println("口香糖已经售罄。不能扭转曲柄!");
    }

    @Override
    public void dispense() {
        System.out.println("口香糖已经售罄。口香糖无法出售!");
    }
}
/**
 * 口香糖售卖状态类
 */
public class SoldState implements State {

    private GumballMachine gumballMachine;

    public SoldState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    @Override
    public void insertCoin() {
        System.out.println("口香糖正在出货中,请稍等。无须再次投入钱币!");
    }

    @Override
    public void undoCoin() {
        System.out.println("口香糖正在出货中,请稍等。不能退回钱币!");
    }

    @Override
    public void turnCrank() {
        System.out.println("口香糖正在出货中,请稍等。不需要再次扭转曲柄!");
    }

    @Override
    public void dispense() {
        if (gumballMachine.getCount() > 0) {
            System.out.println("口香糖正在出货中,请稍等!");
            gumballMachine.releaseBall();
            gumballMachine.setState(gumballMachine.getNoCoinState()); // 状态流转
        } else {
            System.out.println("口香糖库存不足,无法出货!");
            gumballMachine.setState(gumballMachine.getSoldOutState()); // 状态流转
        }
    }
}
@Data
public class GumballMachine {
    private State noCoinState;
    private State hasCoinState;
    private State soldState;
    private State soldOutState;
    private State state = soldOutState; // 口香糖机默认状态为售罄状态
    int count; // 口香糖库存量

    public GumballMachine(int numberGumballs) {
        noCoinState = new NoCoinState(this);
        hasCoinState = new HasCoinState(this);
        soldState = new SoldState(this);
        soldOutState = new SoldOutState(this);
        count = numberGumballs;
        if (numberGumballs > 0)
            state = noCoinState; // 如果采购了口香糖(numberGumballs > 0),则口香糖机的状态为未投币状态
    }

    // 投入钱币
    public void insertCoin() {
        state.insertCoin();
    }

    // 退出钱币
    public void undoCoin() {
        state.undoCoin();
    }

    // 扭转曲柄
    public void turnCrank() {
        state.turnCrank();
        state.dispense();
    }

    // 减少库存
    public void releaseBall() {
        if (count > 0) {
            System.out.println("一个口香糖正在出库");
            --count;
        } else {
            System.out.println("库存不足,一个口香糖无法出库");
        }
    }

    // 设置状态
    void setState(State state) {
        this.state = state;
    }
}

/**
 * 状态模式测试类
 */
public class StateTest {
    public static void main(String[] args) {
        System.out.println("-----向口香糖机中放入1枚口香糖-----");
        GumballMachine machine = new GumballMachine(1);

        System.out.println("-----第一次购买口香糖-----");
        machine.insertCoin();
        machine.undoCoin();
        machine.turnCrank();

        System.out.println("-----第二次购买口香糖-----");
        machine.insertCoin();
        machine.turnCrank();

        System.out.println("-----第三次购买口香糖-----");
        machine.insertCoin();
        machine.turnCrank();
        machine.undoCoin();
    }
}

运行结果:

18. 观察者 Observer ※※※※※

多个对象间存在一对多关系,当一个对象发生改变时,把这种改 变通知给其他多个对象,从而影响其他对象的行为。

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

/**
 * @description 观察者
 * @author: muse
 **/
public interface Observer {

    void update();
}
/**
 * @description 观察者1
 * @author: muse
 **/
public class Observer1 implements Observer {

    public void update() {
        System.out.println("Observer1");
    }
}
/**
 * @description 观察者2
 * @author: muse
 **/
public class Observer2 implements Observer {

    public void update() {
        System.out.println("Observer2");
    }
}
/**
 * @description 观察者3
 * @author: muse
 **/
public class Observer3 implements Observer {

    public void update() {
        System.out.println("Observer3");
    }
}
/**
 * @description 主题类
 * @author: muse
 **/
public interface Subject {

    void registerObserver(Observer observer);

    void removeObserver(Observer observer);

    void notifyObserver();
}
/**
 * @description 主题实现类
 * @author: muse
 **/
public class SubjectImpl implements Subject {

    private List<Observer> observers;

    public SubjectImpl() {
        this.observers = new ArrayList<>();
    }

    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    public void notifyObserver() {
        observers.forEach(observer -> observer.update());
    }
}
/**
 * @description 测试类
 * @author: muse
 **/
public class OberverTest {
    public static void main(String[] args) {
        Observer observer1 = new Observer1();
        Observer observer2 = new Observer2();
        Observer observer3 = new Observer3();
        /** 创建主题 */
        SubjectImpl subject = new SubjectImpl();

        /** 注册三个观察者*/
        subject.registerObserver(observer1);
        subject.registerObserver(observer2);
        subject.registerObserver(observer3);

        /** 发送通知 */
        System.out.println("----------给observer1、observer2、observer3发通知----------");
        subject.notifyObserver();

        /** 移除一个监听者observer2*/
        subject.removeObserver(observer2);
        System.out.println("----------移除了observer2之后发通知----------");
        subject.notifyObserver();
    }
}

运行结果:

19. 中介者 Mediator ※※※※

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

定义:使用中介者模式来集中相关对象之间复杂的沟通和控制方式。

/**
 * 同事类
 */
public abstract class AbstractColleague {

    protected Mediator mediator; // 中介者

    public AbstractColleague(Mediator mediator) {
        this.mediator = mediator;
    }
}
/**
 * 采购人员
 */
public class Purchase extends AbstractColleague {

    public Purchase(Mediator mediator) {
        super(mediator);
    }

    /** 采购电脑 */
    public void buyComputer(int num) {
        System.out.println("执行采购电脑工作!");
        super.mediator.purchaseByComputer(num);
    }

    /** 不再采购电脑 */
    public void refuseBuyComputer() {
        System.out.println("不再采购电脑!");
    }
}
/**
 * 销售人员
 */
public class Sale extends AbstractColleague {

    public Sale(Mediator mediator) {
        super(mediator);
    }

    /** 销售电脑 */
    public void sellComputer(int number) {
        super.mediator.saleSellComputer(number);
        System.out.println("销售电脑" + number + "台");
    }

    /** 获得销售情况(即:售卖了多少台电脑) */
    public int getSaleStatus() {
        // 模拟销售数量
        int sellNumber = new Random(System.currentTimeMillis()).nextInt(100);
        System.out.println("电脑的销售情况为:" + sellNumber + "台");
        return sellNumber;
    }

    /** 折价处理 */
    public void offSale() {
        System.out.println("折价销售电脑");
    }
}
/**
 * 库存人员
 */
public class Stock extends AbstractColleague {

    private static int COMPUTER_NUM = 100; // 电脑的库存量

    public Stock(Mediator mediator) {
        super(mediator);
    }

    /** 增加电脑库存 */
    public void increaseComputer(int number) {
        COMPUTER_NUM += number;
        System.out.println("电脑的库存数量为:" + COMPUTER_NUM);
    }

    /** 减少电脑库存 */
    public void decreaseComputer(int number) {
        COMPUTER_NUM -= number;
        System.out.println("电脑的库存数量为:" + COMPUTER_NUM);
    }

    /** 获得当前电脑的库存 */
    public int getStockNumber() {
        return COMPUTER_NUM;
    }

    /** 清理库存 */
    public void clearStock() {
        System.out.println("清理电脑的库存数量为:" + COMPUTER_NUM);
        super.mediator.stockClear();
    }
}
/**
 * 中介者/调停者
 */
public class Mediator {
    protected Purchase purchase; // 采购人员
    protected Sale sale; // 销售人员
    protected Stock stock; // 库存人员

    public Mediator() {
        purchase = new Purchase(this);
        sale = new Sale(this);
        stock = new Stock(this);
    }

    /** 采购电脑 */
    public void purchaseByComputer(int num) {
        int saleStatus = sale.getSaleStatus();
        // 如果销售情况不好(即:没有超过80台),则采购总数减半
        String msg = "";
        if (saleStatus <= 80) {
            num = num / 2;
            msg = "由于销售不佳,采购总数减半,";
        }
        System.out.println(msg + "原有库存电脑" + stock.getStockNumber() + "台,现采购电脑" + num + "台");
        stock.increaseComputer(num);
    }

    /** 销售电脑 */
    public void saleSellComputer(int num) {
        // 如果库存数量不足,则采购2倍的num电脑数,暂时只售卖库存中有的数量
        int stockNum;
        if ((stockNum = stock.getStockNumber()) < num) {
            purchase.buyComputer(2*num); // 采购两倍数量的电脑
            num = stockNum; // 由于采购到货需要时间,所以暂时只售卖库存中有的数量
        }
        stock.decreaseComputer(num);
    }

    /** 折价销售电脑 */
    public void saleOffSale() {
        sale.offSale();
    }

    /** 清理库存 */
    public void stockClear() {
        sale.offSale(); // 折价销售电脑
        purchase.refuseBuyComputer(); // 不要采购电脑
    }
}
public class MediatorTest {
    public static void main(String[] args) {
        // 创建中介者
        Mediator mediator = new Mediator();

        System.out.println("--------采购人员采购100台电脑--------");
        Purchase purchase = new Purchase(mediator);
        purchase.buyComputer(100);

        System.out.println("--------销售人员销售1台电脑--------");
        Sale sale = new Sale(mediator);
        sale.sellComputer(1);

        System.out.println("--------库房人员清库处理--------");
        Stock stock = new Stock(mediator);
        stock.clearStock();
    }
}

运行结果:

20. 迭代器 Iterator 

不用自己做。

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

定义: 提供一个方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

/**
 * @description
 * @author: muse
 **/
public interface Menu {

    // 获得迭代器
    MenuIterator iterator();
}
/**
 * @description 菜单项
 * @author: muse
 **/
public class MenuItem {
    // 菜名
    private String name;
    // 菜品详细介绍
    private String desc;
    // 是否是素食
    private boolean vegetarian;
    // 菜的价格
    private double price;

    public MenuItem(String name, String desc, boolean vegetarian, double price) {
        this.name = name;
        this.desc = desc;
        this.vegetarian = vegetarian;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }

    public boolean isVegetarian() {
        return vegetarian;
    }

    public double getPrice() {
        return price;
    }
}
/**
 * @description 我们自定义的迭代器
 * @author: muse
 **/
public interface MenuIterator {

    // 容器中是否还有元素
    boolean hasNext();

    // 获得容器中的下一个元素
    MenuItem next();
}
public class ARestaurantMenuIterator implements MenuIterator {

    private ArrayList<MenuItem> menuItems;
    private Iterator<MenuItem> iterator;

    public ARestaurantMenuIterator(ArrayList<MenuItem> menuItems) {
        this.menuItems = menuItems;
        iterator = menuItems.iterator();
    }

    @Override
    public boolean hasNext() {
        return iterator.hasNext();
    }

    @Override
    public MenuItem next() {
        return iterator.next();
    }
}
public class BRestaurantMenuIterator implements MenuIterator {

    private MenuItem[] menuItems;
    private int i = 0;

    public BRestaurantMenuIterator(MenuItem[] menuItems) {
        this.menuItems = menuItems;
    }

    @Override
    public boolean hasNext() {
        return menuItems != null && i < menuItems.length && menuItems[i] != null;
    }

    @Override
    public MenuItem next() {
        return menuItems[i++];
    }
}
/**
 * @description 女招待
 * @author: muse
 **/
public class Waitress {

    /** 服务员打印菜单 */
    public void printMenu(Menu... menus) {
        for (Menu menu : menus) {
            print(menu.iterator());
        }
    }

    private void print(MenuIterator iterator) {
        MenuItem menuItem;
        while (iterator.hasNext()) {
            menuItem = iterator.next();
            System.out.println(String.format("name=%s, desc=%s, price=%s", menuItem.getName(), menuItem.getDesc(),
                    menuItem.getPrice()));
        }
    }
}
/**
 * @description A餐厅的菜单(采用ArrayList存储)
 * @author: muse
 **/
public class ARestaurantMenu implements Menu {

    private ArrayList<MenuItem> menuItems;

    public ARestaurantMenu() {
        menuItems = new ArrayList<>();
        addItem("油条", "油条的描述", true, 0.5);
        addItem("豆浆", "豆浆的描述", true, 1.9);
        addItem("茶叶蛋", "茶叶蛋的描述", true, 1.5);
        addItem("小笼包", "小笼包的描述", true, 2.1);
    }

    private void addItem(String name, String desc, boolean vegetarian, double price) {
        MenuItem menuItem = new MenuItem(name, desc, vegetarian, price);
        menuItems.add(menuItem);
    }

    public ArrayList<MenuItem> getMenuItems() {
        return menuItems;
    }

    @Override
    public MenuIterator iterator() {
        return new ARestaurantMenuIterator(menuItems);
    }
}
/**
 * @description B餐厅的菜单(采用数组存储)
 * @author: muse
 **/
public class BRestaurantMenu implements Menu {
    int nums = 0;
    private static final int MAX_SIZE = 5; // 餐厅老板很有个性,只做5道菜
    private MenuItem[] menuItems;

    public BRestaurantMenu() {
        menuItems = new MenuItem[MAX_SIZE];
        addItem("宫保鸡丁", "宫保鸡丁的描述", true, 0.5);
        addItem("北京烤鸭", "北京烤鸭的描述", true, 1.9);
        addItem("黄焖鸡米饭", "黄焖鸡米饭的描述", true, 1.5);
        addItem("啵啵鱼", "啵啵鱼的描述", true, 2.1);
        addItem("兰州拉面", "兰州拉面的描述", true, 2.1);
    }

    private void addItem(String name, String desc, boolean vegetarian, double price) {
        MenuItem menuItem = new MenuItem(name, desc, vegetarian, price);
        if (nums >= MAX_SIZE) {
            System.out.println("菜单满了!老板不做了!");
            return;
        }
        menuItems[nums++] = menuItem;
    }

    public MenuItem[] getMenuItems() {
        return menuItems;
    }

    @Override
    public MenuIterator iterator() {
        return new BRestaurantMenuIterator(menuItems);
    }
}
/**
 * @description 迭代器模式测试类
 * @author: muse
 **/
public class IteratorTest {
    public static void main(String[] args) {
        /** 构建A餐馆和B餐馆的菜单 */
        ARestaurantMenu aMenu = new ARestaurantMenu();
        BRestaurantMenu bMenu = new BRestaurantMenu();
        /** 构建女服务员 */
        Waitress waitress = new Waitress();
        /** 将A餐馆和B餐馆的菜单传给服务员,让她报出菜单来 */
        waitress.printMenu(aMenu, bMenu);
    }
}

运行结果:

21. 访问者 Visitor ※

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

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

/**
 * @description 电脑组件
 * @author: muse
 **/
public interface ComputerComponent {

    // 售价
    int price();

    // 硬件版本
    String version();

    // 描述
    String desc();

    void accept(Visitor visitor);

}

public class Computer {
    private ComputerComponent memory;
    private ComputerComponent cpu;

    public Computer() {
        memory = new Memory();
        cpu = new Cpu();
    }

    /**
     * 攒机方法
     *
     * @Visitor 买电脑的客户角色
     */
    public void buildComputer(Visitor visitor) {
        // 买cpu
        cpu.accept(visitor);
        // 买内存
        memory.accept(visitor);
    }

}
/**
 * @description CPU
 * @author: muse
 **/
public class Cpu implements ComputerComponent {
    // 全国标准售价
    public int price = 100;

    @Override
    public int price() {
        return 100;
    }

    @Override
    public String version() {
        return "v1";
    }

    @Override
    public String desc() {
        return "英特尔CPU";
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visitorCpu(this);
    }
}
/**
 * @description 内存
 * @author: muse
 **/
public class Memory implements ComputerComponent {
    // 全国标准售价
    public int price = 400;

    @Override
    public int price() {
        return price;
    }

    @Override
    public String version() {
        return "v4";
    }

    @Override
    public String desc() {
        return "金士顿内存";
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visitorMemory(this);
    }
}

/**
 * @description 访问者接口
 * @author: muse
 **/
public interface Visitor {

    // 访问者CPU价格
    void visitorCpu(Cpu cpu);

    // 访问者内存价格
    void visitorMemory(Memory memory);

    // 获得总价
    int price();

    // 访问者名称
    String visiterName();

}
/**
 * @description 公司大客户(因为采购量很大,所以折扣粒度很大)
 * @author: muse
 **/
public class CompanyVisitor implements Visitor {
    // 总售价
    public int totalPrice;

    @Override
    public void visitorCpu(Cpu cpu) {
        totalPrice += cpu.price() * 0.5;
    }

    @Override
    public void visitorMemory(Memory memory) {
        totalPrice += memory.price() * 0.4;
    }

    @Override
    public int price() {
        return totalPrice;
    }

    @Override
    public String visiterName() {
        return "公司大客户";
    }
}
/**
 * @description 个人用户(不打折)
 * @author: muse
 **/
public class PersonVisitor implements Visitor {

    // 总售价
    public int totalPrice;

    @Override
    public void visitorCpu(Cpu cpu) {
        totalPrice += cpu.price();
    }

    @Override
    public void visitorMemory(Memory memory) {
        totalPrice += memory.price();
    }

    @Override
    public int price() {
        return totalPrice;
    }

    @Override
    public String visiterName() {
        return "个人用户";
    }
}
/**
 * @description 学生用户(有学生计划活动,打少量折扣)
 * @author: muse
 **/
public class StudentVisitor implements Visitor {
    // 总售价
    public int totalPrice;

    @Override
    public void visitorCpu(Cpu cpu) {
        totalPrice += cpu.price() * 0.8;
    }

    @Override
    public void visitorMemory(Memory memory) {
        totalPrice += memory.price() * 0.9;
    }

    @Override
    public int price() {
        return totalPrice;
    }

    @Override
    public String visiterName() {
        return "学生用户";
    }
}
public class VisitorTest {
    public static void main(String[] args) {
        Computer computer = new Computer();
        Visitor personVisitor = new PersonVisitor();
        Visitor studentVisitor = new StudentVisitor();
        Visitor companyVisitor = new CompanyVisitor();
        computer.buildComputer(personVisitor);
        System.out.println(String.format("针对%s,每台电脑售价为:%s元", personVisitor.visiterName(), personVisitor.price()));

        computer.buildComputer(studentVisitor);
        System.out.println(String.format("针对%s,每台电脑售价为:%s元", studentVisitor.visiterName(), studentVisitor.price()));

        computer.buildComputer(companyVisitor);
        System.out.println(String.format("针对%s,每台电脑售价为:%s元", companyVisitor.visiterName(), companyVisitor.price()));
    }
}

运行结果:

22. 备忘录 Memento ※

在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。

把创建对象快照的工作委派给实际状态的拥有者。一般用栈保存历史状态。

定义: 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态。当你需要让对象返回之前的状 态时(例如:你的用户请求“撤销”),就使用备忘录模式

/**
 * @description 备忘录
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Memento {

    // 文档内容
    public String content;
}
/**
 * @description 文档类
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Document {

    // 文档的内容
    private String content;

    public void print() {
        System.out.println("content=" + content);
    }
}
/**
 * @description 备忘录管理类
 */
public class MementoManager {
    // 记录备忘录信息
    private Stack<Memento> mementoStack = new Stack<>();

    // 保存备忘录
    public void save(Document document) {
        Memento memento = new Memento(document.getContent());
        mementoStack.add(memento);
    }

    // 撤销操作ctrl+z
    public Document cancel() {
        Memento memento = mementoStack.pop();
        Document document = new Document();
        document.setContent(memento.getContent());
        return document;
    }
}
/**
 * 备忘录测试类
 */
public class MementoTest {
    public static void main(String[] args) {
        MementoManager mementoManager = new MementoManager();
        System.out.println("-----执行文档修改操作-----");
        Document document = new Document();
        document.setContent("a");
        document.print();
        mementoManager.save(document);

        document.setContent("b");
        document.print();
        mementoManager.save(document);

        document.setContent("c"); // 修改后,发现写错了,想要回撤到上一个保存点
        document.print();

        System.out.println("-----执行第一次撤销操作-----");
        document = mementoManager.cancel();
        document.print();

        System.out.println("-----执行第二次撤销操作-----");
        document = mementoManager.cancel();
        document.print();
    }
}

运行结果:

23. 解释器 Interpreter 

提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值