• 深入理解常见的二十三种设计模式


    深入理解常见的二十三种设计模式

    文章目录

    一、设计模式的分类

    设计模式要干的事情就是解耦,创建型模式是把创建和使用代码解耦,结构型模式是将不同够功能代码解耦,行为型模式是将不同的行为代码解耦。

    设计原则和思想其实比设计模式更加普适重要,掌握了代码的设计原则和思想,我们甚至可以创造出来新的设计模式。

    如果只掌握知识,没锻炼能力,遇到实际问题,遇到问题还是没法自己去分析、思考、解决。

    1.1 创建型(五种)

    • 单例模式
    • 工厂模式
    • 抽象工厂模式
    • 建造器模式
    • 原型模式

    记忆:一个单例,两个工厂,一个Builder,一个clone

    1.2 结构型(七种)

    • 适配器模式
    • 装饰模式
    • 代理模式
    • 组合模式
    • 桥接模式
    • 享元模式
    • 外观模式

    记忆:装成另一个角色(适配)、打扮自己是自己更突出(装饰)、让第三方代劳(代理)、合而为一(组合)、多个人搭成桥(桥接)、变成多个自己(享元模式)、做出一个按钮启动所有功能(外观)

    1.3 行为型(十一种)

    • 责任链模式
    • 命令模式
    • 解释器模式
    • 迭代器模式
    • 中介者模式
    • 观察者模式
    • 备忘录模式
    • 模版模式
    • 状态模式
    • 策略模式
    • 参观者模式

    记忆:领导命令(命令模式)拿出一盘大铁链(责任链),解开铁链(解释器),拉动铁链一圈圈的转动(迭代器模式),空中出现一块幕布媒介(中介者模式)、底下坐着众多的观者者(观察者模式),他们手里拿着备忘录(备忘录)、备忘录上有画好的模版(模版)、向里面填写敌军状态(状态)和应对策略(策略),这个时候大门外出现一个人,来视察现场的状态(参观者)。

    二、创建型

    2.1 单例模式

    单例模式:一个类只允许创建一个对象。

    使用场景;对象只需要存在一份,没必须每次使用都创造这个对象。

    写日志的对象、配置信息

    业务概念上,有些数据在系统中只应保存一份。单例还可以解决资源访问冲突的问题(写日志)

    实现思路:1. 把构造函数私有化;2. 考虑线程安全;3. 是否延迟加载;4. getInstance时的性能;

    代码实现的方案:懒汉式、饿汉式、静态内部类、枚举

    (1)懒汉式:用到到时候再创建

    /**
     * 懒汉式: 用到到时候再创建
     * @Date 2022/10/7
     * @Author lifei
     */
    public class Single01 {
    
        private Single01(){}
    
        /**
         * 使用volatile的作用:1. 禁止指令重排; 2. 变量不会再多个线程中存在多个副本,直接从主内粗读取
         * (volatile只在jdk1.5之后有用)
         *
         *  instance = new Single01();  会被拆分成三个指令
         *  1. 为 instance分配内存空间;
         *  2. 调用 Single01 构造函数为其初始化;
         *  3. 将instance对象指向分配的内存空间;
         *
         *  指令可以 1-2-3 顺序执行,如果指令重排 可能会以 1-3-2 顺序执行
         *  第一个线程执行 1-3 后,此时instance已经不为null,但还没有初始化,第二个线程抢用instance,就会出错
         */
        private volatile static Single01 instance;
    
        public static Single01 instance() {
            if (instance==null) {
                synchronized(Single01.class) {
                    if (instance==null) {
                        instance = new Single01();
                    }
                }
            }
            return instance;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    (2)饿汉式:类加载到时候,就把实例对像创建好

    这样方式,在类加载的时候,就会执行。

    如果我们的构造函数要依赖其它类干一些事情,就不能使用这种把对象的创建委托给类装载器的方式了。

    /**
     * 饿汉式:提前创建好
     * @Date 2022/10/7
     * @Author lifei
     */
    public class Single02 {
    
        private Single02(){}
    
        private final static Single02 instance = new Single02();
    
        public static Single02 instance() {
            return instance;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    (3)静态内部类

    只有在调用instance()的时候,才会把实例创建出来。

    InstanceHolder是一个静态内部类,当外部类 Single03被加载的时候,并不会创建 InstanceHolder实例对象。只有当调用 instance() 方法时,InstanceHolder才会被加载,这个时候才会创建 instance。instance 的唯一性、创建过程的线程安全性,都由 JVM 来保证。所以,这种实现方法既保证了线程安全,又能做到延迟加载。

    /**
     * @Date 2022/10/7
     * @Author lifei
     */
    public class Single03 {
        
        private Single03() {}
        
        private static class InstanceHolder {
            private static final Single03 instance = new Single03();
        }
        public static Single03 instance() {
            return InstanceHolder.instance;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    (4)枚举

    /**
     * 枚举
     * @Date 2022/10/7
     * @Author lifei
     */
    public enum Single04Enum {
        INSTANCE;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    单例模式的缺陷:

    • 对代码扩展性不好(从单例,变成多例);
    • 单例不支持有参数的构造函数;
    • 单例对代码的可测性不好;

    唯一的范围:

    • 进程内唯一

    • 线程内唯一:使用Map

    • 集群环境下的唯一

      我们需要把这个单例对象序列化并存储到外部共享存储区(比如文件)。进程在使用这个单例对象的时候,需要先从外部共享存储区中将它读取到内存,并反序列化成对象,然后再使用,使用完成之后还需要再存储回外部共享存储区。

    多例模式:一个类可以创建多个对象,但是个数是有限制的。也可以理解为,同一类型的只能创建一个对象,不同类型的可以创建多个对象。

    2.2 工厂方法模式

    所有工厂模式都是用来封装对象的创建。工厂方法模式通过让自类决定该创建的对象是什么。

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

    从简单工厂,到工厂方法模式,再到抽象工厂模式

    (1)初始代码:根据类型创建Pizza

    public class Pizza {
    
        public void prepare() {
            System.out.println("prepare...");
        }
    
        public void bake() {
            System.out.println("bake...");
        }
    
        public void cut() {
            System.out.println("cut...");
        }
    
        public void box() {
            System.out.println("box....");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    /**
     *  根据type创建不同种类的Pizza
     * @Date 2022/10/7
     * @Author lifei
     */
    public class PizzaStore {
        
        public Pizza orderPizza(String type) {
            Pizza pizza;
            if (type.equals("cheese")) {
                pizza = new CheesePizza();
            } else if (type.equals("veggie")) {
                pizza = new VeggiePizza();
            } else {
                pizza = new Pizza();
            }
            
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    (2)简单工厂:将创建Pizza的功能抽象出来,就变成了简单工厂

    简单工厂不是一个设计模式,更像一种编程习惯。

    /**
     * 简单工厂:不是一种设计模式,更像一种编程习惯
     * @Date 2022/10/7
     * @Author lifei
     */
    public class SimplePizzaFactory {
        
        public Pizza createPizza(String type) {
            Pizza pizza;
            if (type.equals("cheese")) {
                pizza = new CheesePizza();
            } else if (type.equals("veggie")) {
                pizza = new VeggiePizza();
            } else {
                pizza = new Pizza();
            }
            return pizza;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    **
     *  根据type创建不同种类的Pizza
     * @Date 2022/10/7
     * @Author lifei
     */
    public class PizzaStore {
    
        private SimplePizzaFactory pizzaFactory;
    
        public PizzaStore(SimplePizzaFactory pizzaFactory) {
            this.pizzaFactory = pizzaFactory;
        }
    
        public Pizza orderPizza(String type) {
            /*Pizza pizza;
            if (type.equals("cheese")) {
                pizza = new CheesePizza();
            } else if (type.equals("veggie")) {
                pizza = new VeggiePizza();
            } else {
                pizza = new Pizza();
            }*/
            Pizza pizza = pizzaFactory.createPizza(type);
    
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    (3)工厂方法模式:在不同的地区开分店

    这些不同的店,提供个性化的产品,但是也有相同规格的约束。因此对不同地区的店进行抽象:

    public abstract class AbstractPizzaStore {
        
        // 个性化的产品由地区决定
        abstract Pizza createPizza(String type);
    
        public Pizza orderPizza(String type) {
            Pizza pizza = createPizza(type);
    
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    河南Pizza:

    /**
     * 河南独特的Pizza
     * @Date 2022/10/7
     * @Author lifei
     */
    public class HeNanPizzaStore extends AbstractPizzaStore {
        @Override
        Pizza createPizza(String type) {
            Pizza pizza;
            if (type.equals("cheese")) {
                pizza = new HeNanCheesePizza();
            } else if (type.equals("veggie")) {
                pizza = new HeNanVeggiePizza();
            } else {
                pizza = new Pizza();
            }
            return pizza;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    天津Pizza:

    /**
     * 河南独特的Pizza
     * @Date 2022/10/7
     * @Author lifei
     */
    public class TianJinPizzaStore extends AbstractPizzaStore {
        @Override
        Pizza createPizza(String type) {
            Pizza pizza;
            if (type.equals("cheese")) {
                pizza = new TianJinCheesePizza();
            } else if (type.equals("veggie")) {
                pizza = new TianJinVeggiePizza();
            } else {
                pizza = new Pizza();
            }
            return pizza;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    工厂方法是抽象的,依靠子类来处理对象的创建。

    abstract Product factoryMethod(String type);
    
    • 1

    2.3 抽象工厂模式

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

    应用:Spring 的依赖注入容器(DI)。

    基于上面工厂方法模式:假如每个地区生产披萨所用的配料表不一样,那么披萨就要依赖配料工厂

    为此,将其Pizza准备配料的方法抽象出来。

    /**
     * 抽象工厂 中的接口类
     */
    public interface PizzaIngredientFactory {
    
        /**
         * 生产 配料01
         * @return
         */
        String createIngredient01();
    
        /**
         * 生产 配料 02
         * @return
         */
        String createIngredient02();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    /**
     * 抽象工厂的 使用
     * @Date 2022/10/7
     * @Author lifei
     */
    public abstract class AbstractPizza {
      
          // 配料
        protected String ingredient;
    
        // 配料抽象工厂
        protected PizzaIngredientFactory pizzaIngredientFactory;
        
        public AbstractPizza(PizzaIngredientFactory pizzaIngredientFactory) {
            this.pizzaIngredientFactory = pizzaIngredientFactory;
        }
    
        /**
         * 准备配料, 具体的
         */
        public abstract void prepare();
    
        public void bake() {
            System.out.println("bake...");
        }
    
        public void cut() {
            System.out.println("cut...");
        }
    
        public void box() {
            System.out.println("box....");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    在具体的披萨中使用抽象工厂:

    /**
     * 具体的Pizza 使用抽象工厂 
     * @Date 2022/10/7
     * @Author lifei
     */
    public class CheesePizza02 extends AbstractPizza{
        // 传递一个具体的配料工厂
        public CheesePizza02(PizzaIngredientFactory pizzaIngredientFactory) {
            super(pizzaIngredientFactory);
        }
    
        // 只使用配料01
        @Override
        public void prepare() {
            this.ingredient01 = pizzaIngredientFactory.createIngredient01();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    一个具体的配料工厂:

    /**
     * 抽象工厂的具体实现
     */
    public class HeNanPizzaIngredientFactory implements PizzaIngredientFactory{
    
        /**
         * 生产 配料01
         * @return
         */
        @Override
        public String createIngredient01() {
            return "HeNan ingredient01";
        }
    
        /**
         * 生产 配料 02
         * @return
         */
        @Override
        public String createIngredient02() {
            return "HeNan ingredient02";
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    抽象工厂模式中使用了工厂方法模式:

    /**
     * 工厂方法模式中的 披萨商店
     * @Date 2022/10/7
     * @Author lifei
     */
    public abstract class AbstractPizzaStore02 {
    
        // 个性化的产品由地区决定
        abstract AbstractPizza createPizza(String type);
    
        public AbstractPizza orderPizza(String type) {
            AbstractPizza pizza = createPizza(type);
    
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    /**
     * 河南独特的Pizza
     * @Date 2022/10/7
     * @Author lifei
     */
    public class HeNanPizzaStore02 extends AbstractPizzaStore02 {
        @Override
        AbstractPizza createPizza(String type) {
            PizzaIngredientFactory pizzaIngredientFactory = new HeNanPizzaIngredientFactory();
            AbstractPizza pizza = null;
            if (type.equals("cheese")) {
                pizza = new CheesePizza02(pizzaIngredientFactory);
            }
            return pizza;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.4 构造器模式

    构造器模式的好处:能够很好的扩展大量的可选参数。

    与工厂模式的区别:工厂模式用于创建不同但相关类型的对象。构建者模式用来创建一种类型的复杂对象。

    /**
     * 营养成分
     * @Date 2022/10/11
     * @Author lifei
     */
    public class NutritionFacts {
    
        private Integer servingSize;
        private Integer servings;
        private Integer calories;
        private Integer fat;
        private Integer sodium;
        private Integer carbohydrate;
    
        public NutritionFacts(){}
        private NutritionFacts(Builder builder){
            this.servingSize = builder.servingSize;
            this.servings = builder.servings;
            this.calories = builder.calories;
            this.fat = builder.fat;
            this.sodium = builder.sodium;
            this.carbohydrate = builder.carbohydrate;
        }
        
        public static Builder builder() {
            return new Builder();
        }
    
        public static class Builder {
    
            private Integer servingSize;
            private Integer servings;
            private Integer calories;
            private Integer fat;
            private Integer sodium;
            private Integer carbohydrate;
    
            public Builder servingSize(Integer servingSize) {this.servingSize = servingSize; return this;}
            public Builder servings(Integer servings) {this.servings = servings; return this;}
            public Builder calories(Integer calories) {this.calories = calories; return this;}
            public Builder fat(Integer fat) {this.fat = fat; return this;}
            public Builder sodium(Integer sodium) {this.sodium = sodium; return this;}
            public Builder carbohydrate(Integer carbohydrate) {this.carbohydrate = carbohydrate; return this;}
            public NutritionFacts build() {
                return new NutritionFacts(this);
            }
        }
      // 省略getter 和 setter 方法
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    使用

    NutritionFacts nutritionFacts = NutritionFacts.builder().carbohydrate(1).servings(2).servingSize(3)
                    .fat(4).calories(5).sodium(6).build();
    
    • 1
    • 2

    构造器模式还可以用于类的层次结构:

    /**
     * 抽象的层级:
     * 子类于子类有共同的属性,也有不一样的属性
     * @Date 2022/10/11
     * @Author lifei
     */
    public abstract class AbstractBox {
    
        protected Integer size;
        protected String color;
    
        public AbstractBox(Builder builder) {
            this.size = builder.size;
            this.color = builder.color;
        }
    
        abstract static class Builder<T extends Builder<T>> {
            protected Integer size;
            protected String color;
    
            // 模拟的self参数:子类必须复写这个方法,返回"this"
            protected abstract T self();
    
            protected abstract AbstractBox build();
    
            public T size(Integer size) {
                this.size = size;
                return self();
            }
    
            public T color(String color) {
                return self();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    一个子类:

    /**
     * 智能盒子
     * @Date 2022/10/11
     * @Author lifei
     */
    public class ZnBox extends AbstractBox{
    
        private Boolean znFlag;
        public ZnBox(Builder builder) {
            super(builder);
            this.znFlag = builder.znFlag;
        }
    
        public static class Builder extends AbstractBox.Builder<Builder> {
    
            private Boolean znFlag;
    
            public Builder znFlag(Boolean znFlag) {
                this.znFlag = znFlag;
                return this;
            }
    
            @Override
            protected Builder self() {
                return this;
            }
    
            // 协变返回类型:子类声明返回超级类中声明的返回类型的子类
            // 它允许客户端无需类型转换就能使用这些了类型
            @Override
            protected ZnBox build() {
                return new ZnBox(this);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    使用:

    ZnBox znBox = new ZnBox.Builder().color("red").size(20).znFlag(true).build();
    
    • 1

    2.5 原型模式

    使用场景:当创建给定的实例的过程很昂贵或很复杂的时候,可以利用对已有对象(原型)进行复制(或叫做拷贝)的方式来创建新对象。这种基于原型来创建对象的方式就叫做原型设计模式,简称原型模式。

    如果对象的创建需要经过复杂的计算(比如排序、计算哈希值),或者需要从非常慢的IO中读取(比如RPC、网络、数据库、文件系统等),这种情况就可以使用原型模式。

    在Java中,Object类的clone() 方法执行的是我们刚刚说的浅拷贝。

    它们只会拷贝对象中的基本数据类型,以及引用对象的内存地址,不会递归的拷贝引用对象本身。

    /**
     * 原型模式
     * @Date 2022/10/16
     * @Author lifei
     */
    public class PhoneNumber implements Cloneable{
    
        private String userName;
        private int[] numbers;
    
        /**
         * clone方法的通用约定: 这个方法返回的对象应该通过调用 super.clone 获取
         *     如果类的clone方法返回的实例不是通过调用super.clone 方法获得,而是通过调用构造七获得,编译器就不会发出警告,
         *     但是该类的子类调用了super.clone方法,得到的对象就会拥有错误的类,并阻止了clone方法的子类正常工作。
         * 协变返回类型: Object 的clone方法 返回的是 Object,但是这个clone方法返回的却是PhoneNumber。
         *
         * @return
         */
        @Override
        public PhoneNumber clone() {
            try {
                PhoneNumber phoneNumber = (PhoneNumber) super.clone();
                phoneNumber.numbers = numbers.clone();
                return phoneNumber;
            } catch (CloneNotSupportedException e) {
                throw new AssertionError(e);
            }
        }
    
        // 省略 getter 和 setter 方法
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    另一种深拷贝一个对象的思路是:先序列化,再反序列化。

            try {
                PhoneNumber phoneNumber = new PhoneNumber();
                phoneNumber.setUserName("小明");
                phoneNumber.setNumbers(new int[]{1, 0, 5, 1, 1});
                // 先进行序列化
                ByteArrayOutputStream bo = new ByteArrayOutputStream();
                ObjectOutputStream oo = new ObjectOutputStream(bo);
                oo.writeObject(phoneNumber);
                // 再进行反序列化
                ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
                ObjectInputStream oi = new ObjectInputStream(bi);
                Object o = oi.readObject();
                System.out.println(o);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    三、结构型

    3.1 适配器模式(adapter)

    适配器模式:将一个类的接口,转换成客户期待的另一个接口。适配器让原本接口不兼容的类可以合作无间。比如,现实中,把USB插头转变成type-C插头。

    将不兼容的接口转变为兼容的接口。是一种事后补救的策略。

    场景:将另一个系统的功能集成到当前的系统中,既不能改变另一个系统的代码,又不能改变当前系统的代码。

    适配器,就像一个转接头。

    适配器模式分为:对象适配器(使用对象的组合)、类适配器。

    java不支持多继承,因此不支持类适配。但某些场景下可以通过 extends Adaptee implements ITarget 来达到类适配。

    对象适配的示例:

    /**
     * 将迭代器适配成枚举
     * @Date 2022/10/16
     * @Author lifei
     */
    public class EnumerationAdapter<T> implements Enumeration<T> {
    
        private Iterator<T> iterator;
    
        public EnumerationAdapter(Iterator<T> iterator) {
            this.iterator = iterator;
        }
        @Override
        public boolean hasMoreElements() {
            return iterator.hasNext();
        }
    
        @Override
        public T nextElement() {
            return iterator.next();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<>();
            list.add("01");
            list.add("03");
            list.add("02");
            EnumerationAdapter<String> adapter = new EnumerationAdapter<>(list.iterator());
            while (adapter.hasMoreElements()) {
                System.out.println(adapter.nextElement());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    类适配:

    public class Adaptee {
    
        public void a1() {
            System.out.println("a1");
        }
        public void b1(){
            System.out.println("b1");
        }
        public void cc() {
            System.out.println("cc");
        }
    }
    
    public interface ITarget {
        void a2();
        void b2();
        void cc();
    }
    
    public class Adapter extends Adaptee implements ITarget {
        @Override
        public void a2() {
            super.a1();
        }
    
        @Override
        public void b2() {
            super.b1();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    3.2 装饰者模式

    通过组合的方式。

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

    装饰器模式相对于简单的组合关系,有两个比较特殊的地方:

    1. 装饰器类和原始类继承同样的父类,这样我们可以对原始类“嵌套”多个装饰器类;
    2. 装饰器类是对功能的增强;

    应用:Java的IO

    父类:

    /**
     * 一个咖啡品牌店
     * @Date 2022/10/16
     * @Author lifei
     */
    public abstract class Beverage {
    
        protected String description = "Unknown Beverage";
    
        public String getDescription() {
            return description;
        }
    
        public abstract double cost();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    子类:某一个饮品

    /**
     * 某一个饮品
     * @Date 2022/10/16
     * @Author lifei
     */
    public class Espresso extends Beverage{
    
        public Espresso() {
            this.description = "Espresso";
        }
        @Override
        public double cost() {
            return 0.89;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    扩展:为饮品添加配料(比如:加糖、加冰、加牛奶等)

    配料装饰器:

    /**
     * 调料装饰器
     * @Date 2022/10/16
     * @Author lifei
     */
    public abstract class CondimentDecorator extends Beverage{
    
        public abstract String getDescription();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    添加摩卡配料:

    /**
     * 添加摩卡配料
     * @Date 2022/10/16
     * @Author lifei
     */
    public class Mocha extends CondimentDecorator{
    
        public Beverage beverage;
        public Mocha(Beverage beverage) {
            this.beverage = beverage;
        }
        @Override
        public double cost() {
            return 0.20 + beverage.cost();
        }
    
        @Override
        public String getDescription() {
            return beverage.getDescription() + ", Mocha";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    使用:

    /**
     * 装饰器的示例
     * @Date 2022/10/16
     * @Author lifei
     */
    public class DecoratorDemo {
    
        public static void main(String[] args) {
            Beverage beverage = new Espresso();
            // Espresso, 价格为: 0.89
            System.out.println(beverage.getDescription() + ", 价格为: " + beverage.cost());
            
            // 添加摩卡
            beverage = new Mocha(beverage);
            // Espresso, Mocha, 价格为: 1.09
            System.out.println(beverage.getDescription() + ", 价格为: " + beverage.cost());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    比如,适配器模式再JavaIO 中的应用:

                InputStream inputStream = new FileInputStream("/DecoratorDemo.java");
                BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
                LineNumberInputStream lineNumberInputStream = new LineNumberInputStream(bufferedInputStream);
    
    • 1
    • 2
    • 3

    3.3 代理模式

    代理:控制和管理访问。

    使用代理的常见情况:

    • 远程代理:

      一个简单的RPC框架。

    • 虚拟代理:需要创建开销很大的对象。

    • 保护代理:可以通过动态代理实现。

    远程代理和虚拟代理:代理对象实现了真实对象的抽象接口,并持有真实对象的引用。

    动态代理:有两种实现方式,一种是JDK 基于接口的动态代理;一种是cglab ,基于继承的动态代理。

    JDK 的 java.lang.reflect,基于接口。

    如果要代理的类作为一个普通的类,没有接口,那么Java的动态代理就没法使用了。

    /**
     * 主题接口
     * @Date 2022/10/17
     * @Author lifei
     */
    public interface PersonBean {
    
        String getName();
        void setName(String name);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    /**
     * 主题的一个实现
     * @Date 2022/10/17
     * @Author lifei
     */
    public class PersonBeanImpl implements PersonBean{
        private String name;
    
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public void setName(String name) {
            this.name = name;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    代理对象的执行方法:

    /**
     * 代理对象的执行
     * @Date 2022/10/17
     * @Author lifei
     */
    public class OwnerInvocationHandler implements InvocationHandler {
    
        private PersonBean personBean;
    
        public OwnerInvocationHandler(PersonBean personBean) {
            this.personBean = personBean;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getName().startsWith("get")) {
                return method.invoke(personBean, args);
            }else if (method.getName().startsWith("set")){
                throw new IllegalAccessException();
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    创建代理对象:

        /**
         * 创建代理对象
         * @param personBean
         * @return
         */
        private static PersonBean getOwnerProxy(PersonBean personBean) {
            return (PersonBean) Proxy.newProxyInstance(personBean.getClass().getClassLoader(), personBean.getClass().getInterfaces(),
                    new OwnerInvocationHandler(personBean));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    测试:

        public static void main(String[] args) {
            PersonBean personBean = new PersonBeanImpl();
            personBean.setName("001");
            PersonBean ownerProxy = getOwnerProxy(personBean);
            System.out.println(ownerProxy.getName());
            ownerProxy.setName("002"); // 报错
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    CGLIB动态代理,动态的生成一个要代理的子类。

    CGLIB的缺点是,对final方法无法处理。

    /**
     * 目标类
     * @Date 2022/10/17
     * @Author lifei
     */
    public class TargetObject {
        public void a() {
            System.out.println("方法a 执行了");
            b();
        }
        public void b() {
            System.out.println("方法b执行了");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    /**
     * 方法拦截
     * @Date 2022/10/17
     * @Author lifei
     */
    public class TargetInterceptor implements MethodInterceptor {
    
        private TargetObject targetObject;
    
        public TargetInterceptor(TargetObject targetObject) {
            this.targetObject = targetObject;
        }
    
        /**
         *
         * @param o 目标对象
         * @param method 目标对象方法
         * @param params 目标对象方法参数
         * @param methodProxy CGLIB代理方法对象
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Object o, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
            System.out.println("方法调用前");
            // invoke 与 invokeSuper 的区别: https://www.cnblogs.com/lvbinbin2yujie/p/10284316.html
            // invoke 调用的对象是没有增强过,invokeSuper调用的雕像是增强过
    //        Object result = methodProxy.invokeSuper(o, params);
    //        Object result = methodProxy.invokeSuper(targetObject, params);  // 会报错
            Object result = methodProxy.invoke(targetObject, params);
    //        Object result = methodProxy.invoke(o, params);  // 获报错
            System.out.println("方法调用后");
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    创建代理对象,及使用:

    /**
     * 演示CGLIB
     * @Date 2022/10/17
     * @Author lifei
     */
    public class DemoCGLIB {
    
        public static void main(String[] args) {
            TargetObject target = new TargetObject();
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(TargetObject.class);
            enhancer.setCallback(new TargetInterceptor(target));
    
            TargetObject targetObject = (TargetObject) enhancer.create();
            targetObject.a();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3.4 桥接模式

    桥接模式:将抽象与实现解耦,让它们可以独立变化。

    应用:JDBC驱动是桥接模式的典型应用。

    JDBC中,抽象是一套“类库”,具体的Driver(比如,com.mysql.jdbc.Driver)就相当于实现。这里的实现,并非接口的实现,而是跟具体数据库相关的一套“类库”。JDBC和Driver独立开发,通过对象之间的组合关系,组装在一起。JDBC的多有逻辑操作,最终都委托给Driver来执行。

    3.5 享元模式

    享元:共享的单元。

    享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。

    当一个系统存在大量重复对象的时候,如果这些重复对象是不可变对象。可以利用享元模式将对象设计为享元,在内存中只保留一份实例,供多处代码引用。

    享元模式与单例模式的对比:在单例模式中,一个类只能创建一个对象。而在享元模式中,一个类可以创建多个对象,每个对象被多处代码引用共享。(享元模式有点类似,单例的变体:多例)。

    享元模式与缓存:在享元模式中,通过工厂类来“缓存”已经创建好的对象。和我们平时所说的缓存“数据库缓存”、“CPU缓存”、“MemCache缓存”是两回事。平时所说的缓存主要是为了提高访问效率,而非复用。

    享元模式与池化技术(连接池、线程池)的区别:池化技术的“复用”,可以理解为重复使用,主要是为了节约时间(不需要重新创建),在任一时刻,是被一是使用者独占,使用完了,放回迟中,再由其他使用者重复使用。享元模式中的“复用”,可以理解为“共享使用”,在整个生命周期中,都是被所有使用者共享的,主要目的是节省空间。

    应用:

    享元模式在Java Integer中的使用:

    当我们通过自动装箱,也就是调用 valueOf() 来创建 Integer 对象的时候,如果要创建的 Integer 对象的值在 -128 到 127 之间,会从 IntegerCache 类中直接返回,否则才调用 new 方法创建。

    JDK 也提供了方法来让我们可以自定义缓存的最大值,JDK 并没有提供设置最小值的方法。

    //方法一:
    -Djava.lang.Integer.IntegerCache.high=255
    //方法二:
    -XX:AutoBoxCacheMax=255

    除了Integer ,其它的包装器类型,比如Long、Short、Byte等,也都利用了享元模式来缓存 -128 到 127 之间的数据。

            Integer val01 = Integer.valueOf(20);
            Integer val02 = Integer.valueOf(20);
            Integer val03 = new Integer(20);
            System.out.println(val01 == val02); // false
            System.out.println(val01 == val03); // ture
    
    • 1
    • 2
    • 3
    • 4
    • 5

    构造函数创建的方式,不会用到IntegerCache。

    享元模式在Java String中的使用:

            String str01 = "你好";
            String str02 = "你好";
            String str03 = new String("你好");
            System.out.println(str01==str02); // true
            System.out.println(str01==str03); // false
    
    • 1
    • 2
    • 3
    • 4
    • 5

    String 类利用享元模式来复用相同的字符串常量。JVM 会专门开辟一块存储区来存储字符串常量,这块存储区叫作“字符串常量池”。类似于 Integer 中的 IntegerCache。不过,跟 IntegerCache 不同的是,它并非事先创建好需要共享的对象,而是在程序的运行期间,根据需要来创建和缓存字符串常量。

    软引用、弱引用、Weakhashmap。

    https://www.baeldung.com/java-weakhashmap

    https://www.baeldung.com/java-soft-references

    https://www.baeldung.com/java-weak-reference

    3.6 外观模式

    外观模式,又叫门面模式:为子系统提供一组统一的接口,定义一组高层接口让子系统更容易用。

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

    外观模式和“最少知识”原则(迪米特法则)的关系:只和你的密友谈话。

    最少知识原则:每个模块(unit)只应该了解那些与它关系密切的模块(units: only units “closely” related to the current unit)的有限知识(knowledge)。或者说,每个模块只和自己的朋友“说话”(talk),不和陌生人“说话”(talk)。

    3.7 组合模式

    组合模式常和迭代器模式一起使用。

    组合模式,主要用于处理树形结构数据。

    将一组对象(文件和目录)组织成树形结构,以表示一种‘部分 - 整体’的层次结构(目录与子目录的嵌套结构)。组合模式让客户端可以统一单个对象(文件)和组合对象(目录)的处理逻辑(递归遍历)

    将一组对象(员工和部门)组织成树形结构,以表示一种‘部分 - 整体’的层次结构(部门与子部门的嵌套结构)。组合模式让客户端可以统一单个对象(员工)和组合对象(部门)的处理逻辑(递归遍历)

    (1)示例一:文件和目录
    /**
     * 目录和文件的抽象
     * @Date 2022/10/20
     * @Author lifei
     */
    public abstract class FileSystemNodeParent {
        protected String path;
        public FileSystemNodeParent(String path) {
            this.path = path;
        }
        
        public abstract int countNumberOfFiles();
    
        public abstract long countSizOfFiles();
    
        public String getPath() {
            return path;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    /**
     * 目录的实现
     * @Date 2022/10/20
     * @Author lifei
     */
    public class DirectoryItem extends FileSystemNodeParent{
    
        private List<FileSystemNodeParent> subNodes = new ArrayList<>();
    
        public DirectoryItem(String path) {
            super(path);
        }
    
        @Override
        public int countNumberOfFiles() {
            int res = 0;
            for (FileSystemNodeParent fileDir : subNodes) {
                res += fileDir.countNumberOfFiles();
            }
            return res;
        }
    
        @Override
        public long countSizOfFiles() {
            long res = 0;
            for (FileSystemNodeParent fileDir : subNodes) {
                res += fileDir.countSizOfFiles();
            }
            return res;
        }
    
        public void addSubNode(FileSystemNodeParent fileSystemNode) {
            this.subNodes.add(fileSystemNode);
        }
    
        public void removeSubNode(FileSystemNodeParent fileSystemNode) {
            int size = subNodes.size();
            int i = 0;
            for (; i<subNodes.size(); i++) {
                if (StringUtils.equals(subNodes.get(i).getPath(), fileSystemNode.path)) {
                    break;
                }
            }
            if (i<subNodes.size()) {
                subNodes.remove(i);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    /**
     * 文件的实现
     * @Date 2022/10/20
     * @Author lifei
     */
    public class FileItem extends FileSystemNodeParent {
    
        public FileItem(String path) {
            super(path);
        }
    
        @Override
        public int countNumberOfFiles() {
            return 1;
        }
    
        @Override
        public long countSizOfFiles() {
            File file = new File(path);
            if (!file.exists()) {
                return 0l;
            }
            return file.length();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    /**
     * 组合模式的测试: 文件-目录 对象,使用组合模式
     * @Date 2022/10/20
     * @Author lifei
     */
    public class FileTreeDemo {
    
        public static void main(String[] args) {
            String dirPath = "/Users/lifei/Documents/workspace/githubRepositoies/JavaNoneRebuild/projects/javaActionPro/action-design-patterns/src";
            DirectoryItem directoryItem = createDirectoryItem(dirPath);
            System.out.println("文件的数量:" + directoryItem.countNumberOfFiles());
            System.out.println("文件的大小:" + directoryItem.countSizOfFiles());
        }
    
        /**
         * 根据根目录创建,一个文件树
         * @param dirPath
         * @return
         */
        public static DirectoryItem createDirectoryItem(String dirPath) {
            File file = new File(dirPath);
            if (StringUtils.isBlank(dirPath) || !file.exists() || file.isFile()) {
                throw new RuntimeException("必须传递一个目录");
            }
            DirectoryItem directoryItem = new DirectoryItem(dirPath);
            String[] fileNames = file.list();
            for (String fileName : fileNames) {
                String subFilePath = dirPath + File.separator + fileName;
                File subFile = new File(subFilePath);
                if (subFile.isFile()) {
                    directoryItem.addSubNode(new FileItem(subFilePath));
                }else {
                    directoryItem.addSubNode(createDirectoryItem(subFilePath));
                }
            }
            return directoryItem;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    (2)示例二:组合模式和迭代器模式一块使用

    组合模式的抽象:包含叶子和非叶子结点的所有方法

    /**
     * 菜单组件:包含了叶子和组合 的所有方法
     * @Date 2022/10/29
     * @Author lifei
     */
    public abstract class MenuComponent {
    
        public void add(MenuComponent menuComponent) {
            throw new UnsupportedOperationException();
        }
    
        public void remove(MenuComponent menuComponent) {
            throw new UnsupportedOperationException();
        }
    
        public void getChild(int i) {
            throw new UnsupportedOperationException();
        }
    
        public String getName() {
            throw new UnsupportedOperationException();
        }
    
        public String getDescription() {
            throw new UnsupportedOperationException();
        }
    
        public boolean isVegetarian() {
            throw new UnsupportedOperationException();
        }
    
        public double getPrice() {
            throw new UnsupportedOperationException();
        }
    
        public void print() {
            throw new UnsupportedOperationException();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    叶子结点:

    /**
     * 菜单项
     * @Date 2022/10/29
     * @Author lifei
     */
    public class MeanItem extends MenuComponent{
    
        private final String name;
        private final String description;
        private final boolean vegetarian;
        private final double price;
    
        public MeanItem(String name, String description, boolean vegetarian, double price) {
            this.name = name;
            this.description = description;
            this.vegetarian = vegetarian;
            this.price = price;
        }
    
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public String getDescription() {
            return description;
        }
    
        @Override
        public boolean isVegetarian() {
            return vegetarian;
        }
    
        @Override
        public double getPrice() {
            return price;
        }
    
        @Override
        public void print() {
            String res = MoreObjects.toStringHelper(MeanItem.class)
                    .add("name", name)
                    .add("description", description)
                    .add("vegetarian", vegetarian)
                    .add("price", price)
                    .toString();
            System.out.println(res);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    非叶子结点:

    /**
     * 菜单
     * @Date 2022/10/29
     * @Author lifei
     */
    public class Menu extends MenuComponent{
    
        private List<MenuComponent> menuComponents = new ArrayList<>();
    
        private String name;
        private String description;
    
        public Menu(String name, String description) {
            this.name = name;
            this.description = description;
        }
    
        public List<MenuComponent> getMenuComponents() {
            return menuComponents;
        }
    
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public String getDescription() {
            return description;
        }
    
        @Override
        public void add(MenuComponent menuComponent) {
            this.menuComponents.add(menuComponent);
        }
    
        @Override
        public void remove(MenuComponent menuComponent) {
            this.menuComponents.remove(menuComponent);
        }
    
        @Override
        public void getChild(int i) {
            this.menuComponents.get(i);
        }
    
        @Override
        public void print() {
            String res = MoreObjects.toStringHelper(Menu.class)
                    .add("name", name)
                    .add("description", description)
                    .toString();
            System.out.println(res);
            System.out.println("-----------------");
            Iterator<MenuComponent> iterator = menuComponents.iterator();
            while (iterator.hasNext()) {
                MenuComponent menuComponent = iterator.next();
                menuComponent.print();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    使用组合的抽象:

    /**
     * 服务员
     * @Date 2022/10/29
     * @Author lifei
     */
    public class Waitress {
        private MenuComponent menuComponent;
    
        public Waitress(MenuComponent menuComponent) {
            this.menuComponent = menuComponent;
        }
    
        public void printMenu() {
            menuComponent.print();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    演示组合模式:

    /**
     * 示例:组合模式 + 迭代器模式
     * @Date 2022/10/29
     * @Author lifei
     */
    public class ApplicationDemo {
    
        public static void main(String[] args) {
            MenuComponent allMenus = new Menu("所有的菜单", "所有的菜单组合");
            // 一级菜单
            MenuComponent pancakeHouseMenu = new Menu("煎饼屋", "早餐");
            MenuComponent dinerMenu = new Menu("大餐", "晚餐");
            MenuComponent cafeMenu = new Menu("咖啡屋", "饮品");
    
            allMenus.add(pancakeHouseMenu);
            allMenus.add(dinerMenu);
            allMenus.add(cafeMenu);
    
            // 二级菜单
            pancakeHouseMenu.add(new MeanItem("Pancake01", "001",  false, 2.99));
            pancakeHouseMenu.add(new MeanItem("Pancake02", "002",  true, 3.99));
            pancakeHouseMenu.add(new MeanItem("Pancake03", "003",  false, 1.99));
            pancakeHouseMenu.add(new MeanItem("Pancake04", "004",  true, 5.99));
    
            Waitress waitress = new Waitress(allMenus);
            waitress.printMenu();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    三、行为型

    3.1 职责链模式

    职责链模式:将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一个链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。

    (1)职责链的第一种实现方式:用链表存放处理器

    定义一个抽象的Handler,相当于职责链上的一个节点。

    /**
     * 职责链模式:第一种实现方案
     * 定义一个抽象的Handler,handler 是抽象方法。
     *     1. 每个处理器 handle() 函数的代码结构类似。
     *     2. 如果它能处理请求,就bu不继续向下传递;
     *     3. 如果它不能处理,则由后面的处理器来处理(也就是调用 successor.handler() 来处理)
     * @Date 2022/10/23
     * @Author lifei
     */
    public abstract class Handler {
    
        protected Handler successor = null;
    
        public void setSuccessor(Handler successor) {
            this.successor = successor;
        }
    
        public abstract void handle();
    }
    
    /**
     * 处理器A
     * @Date 2022/10/23
     * @Author lifei
     */
    public class AHandler extends Handler{
    
        @Override
        public void handle() {
            boolean handled = false;
            //.... 判断当前处理其链是否可以操作,如果可以操作将 handled设置为true
            if (!handled && successor!=null) {
                successor.handle();
            }
    
        }
    }
    
    /**
     * 处理器B
     * @Date 2022/10/23
     * @Author lifei
     */
    public class BHandler extends Handler{
        @Override
        public void handle() {
            boolean handled = false;
            //...... 判断当前处理其链是否可以操作,如果可以操作将 handled设置为true
            if (!handled && successor!=null) {
                successor.handle();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    定义处理器链的结构:HandlerChain

    /**
     * 处理器链:
     *  从数据结构的角度来看,它就是一个记录了链头、链尾的链表。
     *  其中,记录链尾,是为了方便添加处理器
     * @Date 2022/10/23
     * @Author lifei
     */
    public class HandlerChain {
    
        private Handler head, tail;
        /**
         * 添加处理器
         * @param handler
         */
        public void addHandler(Handler handler) {
            handler.setSuccessor(null);
            if (head==null) {
                head = handler;
                tail = handler;
                return;
            }
            tail.setSuccessor(handler);
            tail = handler;
        }
    
        public void handle() {
            if (head!=null) {
                head.handle();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在上面的实现中,AHandler和BHandler的handle()方法有共同的模版,因此可以使用模版方法模式进行优化:

    public abstract class Handler {
    
        protected Handler successor = null;
    
    //    public abstract void handle();
    
        public final void handle() {
            boolean handled = doHandle();
            if (!handled && Objects.nonNull(successor)) {
                successor.handle();
            }
        }
    
        protected abstract boolean doHandle();
    
        public void setSuccessor(Handler successor) {
            this.successor = successor;
        }
    }
    
    
    public class AHandler extends Handler{
      
        @Override
        protected boolean doHandle() {
            boolean handled = false;
            // 看是否能在当前处理器处理,如果能成功处理,返回true,否则返回false。
            return handled;
        }
    }
    
    public class BHandler extends Handler{
      
        @Override
        protected boolean doHandle() {
            boolean handled = false;
            // 看是否能在当前处理器处理,如果能成功处理,返回true,否则返回false。
            return handled;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    使用举例:

    /**
     * 使用举例
     * @Date 2022/10/23
     * @Author lifei
     */
    public class Application {
    
        public static void main(String[] args) {
            HandlerChain handlerChain = new HandlerChain();
            handlerChain.addHandler(new AHandler());
            handlerChain.addHandler(new BHandler());
            handlerChain.handle();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    (2)职责链的第二种实现方式:用数组存放处理器

    责任链的节点:处理器

    public interface IHandler {
    
        boolean handle();
    }
    
    public class HandlerA implements IHandler{
        @Override
        public boolean handle() {
            boolean handled = false;
            // ...... 判断当前处理其是否能处理,如果能处理返回ture,否则,返回false
            return handled;
        }
    }
    
    public class HandlerB implements IHandler{
        @Override
        public boolean handle() {
            boolean handled = false;
            // ...... 判断当前处理其是否能处理,如果能处理返回ture,否则,返回false
            return handled;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    /**
     * 处理器链的第二种实现方案:使用数组来存放处理器
     * @Date 2022/10/23
     * @Author lifei
     */
    public class HandlerChain {
        private List<IHandler> handlers = new ArrayList<>();
    
        public void addHandler(IHandler handler) {
            this.handlers.add(handler);
        }
    
        public void handle() {
            for (IHandler handler : handlers) {
                boolean handled = handler.handle();
                if (handled) {
                    break;
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    /**
     * 使用举例
     * @Date 2022/10/23
     * @Author lifei
     */
    public class Application {
    
        public static void main(String[] args) {
            HandlerChain handlerChain = new HandlerChain();
            handlerChain.addHandler(new HandlerA());
            handlerChain.addHandler(new HandlerB());
            handlerChain.handle();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    (3)职责链的一种变种:请求会被所有的处理器都处理一遍,不存在中途终止的情况

    这种变种只需要稍微修改,把上面的终止条件去掉。

    用链表存放处理器,的处理器

    public abstract class Handler {
    
        protected Handler successor = null;
    
        public final void handle() {
            doHandle();
            if (Objects.nonNull(successor)) {
                successor.handle();
            }
        }
    
        protected abstract void doHandle();
    
        public void setSuccessor(Handler successor) {
            this.successor = successor;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    用数组存放处理器的处理器链:

    /**
     * 处理器链的第二种实现方案:使用数组来存放处理器
     * @Date 2022/10/23
     * @Author lifei
     */
    public class HandlerChain {
        private List<IHandler> handlers = new ArrayList<>();
    
        public void addHandler(IHandler handler) {
            this.handlers.add(handler);
        }
    
        public void handle() {
            for (IHandler handler : handlers) {
                if (Objects.nonNull(handler)) {
                    handler.handle();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    (4)应用场景:论谈发帖审核
    /**
     * 敏感词过滤
     * @Date 2022/10/23
     * @Author lifei
     */
    public abstract class SensitiveWordFilter {
    
        private SensitiveWordFilter successor;
    
        public void setSuccessor(SensitiveWordFilter successor) {
            this.successor = successor;
        }
    
        public final boolean filter(Context context) {
            boolean legal = doFilter(context);
            if (legal && Objects.nonNull(successor)) {
                return successor.filter(context);
            }
            return legal;
        }
    
        public abstract boolean doFilter(Context context);
    }
    
    /**
     * 性关键词过滤
     * @Date 2022/10/23
     * @Author lifei
     */
    public class SexyWordFilter extends SensitiveWordFilter{
        @Override
        public boolean doFilter(Context context) {
            boolean legal = false;
            // 判断是否合法
            return legal;
        }
    }
    
    /**
     * 政治敏感词过滤
     * @Date 2022/10/23
     * @Author lifei
     */
    public class PoliticalWordFilter extends SensitiveWordFilter{
    
        @Override
        public boolean doFilter(Context context) {
            boolean legal = false;
            // 过滤政治敏感词
            return legal;
        }
    }
    
    /**
     * 广告法敏感词过滤
     * @Date 2022/10/23
     * @Author lifei
     */
    public class AdsWordFilter extends SensitiveWordFilter{
        @Override
        public boolean doFilter(Context context) {
            boolean legal = false;
            // 看是否符合广告法
            return legal;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    过滤器链:

    /**
     * 敏感词过滤链
     * @Date 2022/10/23
     * @Author lifei
     */
    public class SensitiveWordFilterChain {
        private SensitiveWordFilter head, tail;
    
        public void addSensitiveWordFilter(SensitiveWordFilter sensitiveWordFilter) {
            sensitiveWordFilter.setSuccessor(null);
            if (Objects.nonNull(head)) {
                this.head = sensitiveWordFilter;
                this.tail = sensitiveWordFilter;
                return;
            }
            this.tail.setSuccessor(sensitiveWordFilter);
            this.tail = sensitiveWordFilter;
        }
    
        public boolean filter(Context context) {
            boolean legal = true;
            if (Objects.nonNull(head)) {
                legal = head.filter(context);
            }
            return legal;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    /**
     * 应用示例:过滤敏感词
     * @Date 2022/10/23
     * @Author lifei
     */
    public class ApplicationSensitiveWordFilter {
    
        public static void main(String[] args) {
            SensitiveWordFilterChain sensitiveWordFilterChain = new SensitiveWordFilterChain();
            sensitiveWordFilterChain.addSensitiveWordFilter(new SexyWordFilter());
            sensitiveWordFilterChain.addSensitiveWordFilter(new PoliticalWordFilter());
            sensitiveWordFilterChain.addSensitiveWordFilter(new AdsWordFilter());
    
            boolean legal = sensitiveWordFilterChain.filter(new Context());
            if (legal) {
                // 发表
            } else {
                // 不发表
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    (5)职责链在开发框架中的应用:过滤器(Servlet Filter)

    Servlet Filter是Servlet规范的一部分,实现依赖于Web容器。

    (6)职责链在开发框架中的应用:拦截器(Spring Interceptor)

    Spring Interceptor是Spring MVC框架的一部分,由Spring MVC框架来提供实现的。

    客户端发送的请求,会先经过Servlet Filter,然后再经过Spring Interceptor,最后到达具体的业务代码中。

    (7)AOP(面向切面)、Servlet Filter(过滤器)、Spring Intercepter(拦截器)都可以做访问控制功能,区别是什么?

    servlet filter 作用于容器,应用范围影响很大;Spring Intercepter (拦截器)作用于框架,范围影响适中;AOP 作用于业务逻辑,精细化处理,范围影响很小。

    3.2 解释器模式

    解释器模式:为某个语言定义它的语法(或者叫文法)表示,并定义一个解释器用来处理这个语法。

    (1)示例一:根据计算规则,获取输入内容的结果
    版本一:不使用解释器模式

    如果表达式很复杂,这个类就会很大。

    /**
     * 未使用解释器模式
     *   假设我们定义了一个新的加减乘除计算“语言”,语法规则如下:
     *   1. 运算符只包含加、减、乘、除,并且没有优先级的概念;
     *   2. 表达式(也就是前面提到的“句子”)中,先书写数字,后书写运算符,空格隔开;
     *   3. 按照先后顺序,取出两个数字和一个运算符计算结果,结果重新放入数字的最头部位置,
     *      循环上述过程,直到只剩下一个数字,这个数字就是表达式最终的计算结果。
     * @Date 2022/11/5
     * @Author lifei
     */
    public class ExpressionInterpreter {
    
        public long interpreter(String expression) {
            Deque<Long> deque = new LinkedList<>();
            String[] elements = expression.split(" ");
            int lastNumIndex = elements.length/2;
            // 拿到数字
            for (int i=0; i<=lastNumIndex; i++) {
                deque.add(Long.parseLong(elements[i]));
            }
            // 获取运算符
            for (int i=lastNumIndex+1; i<elements.length; i++) {
                String operator = elements[i];
                boolean valid = StringUtils.equals(operator, "+") || StringUtils.equals(operator, "-")
                        || StringUtils.equals(operator, "*") || StringUtils.equals(operator, "/");
                if (!valid) {
                    throw new IllegalArgumentException("无效的表达式:" + expression);
                }
                long firstVal =  deque.pollFirst();
                long secondVal = deque.pollFirst();
                long res = 0;
                if (StringUtils.equals(operator, "+")) {
                    res = firstVal + secondVal;
                }else if (StringUtils.equals(operator, "-")) {
                    res = firstVal - secondVal;
                }else if (StringUtils.equals(operator, "*")) {
                    res = firstVal * secondVal;
                } else {
                    res = firstVal/secondVal;
                }
                deque.addFirst(res);
            }
    
            if (deque.size()!=1) {
                throw new RuntimeException("无效的表达式:" + expression);
            }
            return deque.pop();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    版本二:使用解释器模式进行重构
    /**
     * 表达式接口
     * @Date 2022/11/5
     * @Author lifei
     */
    public interface Expression {
        long interpreter();
    }
    
    /**
     * 数值表达式
     * @Date 2022/11/5
     * @Author lifei
     */
    public class NumberExpression implements Expression{
    
        private long number;
    
        public NumberExpression(long number) {
            this.number = number;
        }
    
        public NumberExpression(String number) {
            this.number = Long.parseLong(number);
        }
    
        @Override
        public long interpreter() {
            return number;
        }
    }
    
    /**
     * 加法表达式
     * @Date 2022/11/5
     * @Author lifei
     */
    public class AdditionExpression implements Expression {
    
        private Expression expression1;
        private Expression expression2;
    
        public AdditionExpression(Expression expression1, Expression expression2) {
            this.expression1 = expression1;
            this.expression2 = expression2;
        }
    
        @Override
        public long interpreter() {
            return expression1.interpreter() + expression2.interpreter();
        }
    }
    
    /**
     * 减法表达式
     * @Date 2022/11/5
     * @Author lifei
     */
    public class SubtractionExpression implements Expression {
    
        private Expression expression1;
        private Expression expression2;
    
        public SubtractionExpression(Expression expression1, Expression expression2) {
            this.expression1 = expression1;
            this.expression2 = expression2;
        }
    
        @Override
        public long interpreter() {
            return expression1.interpreter() - expression2.interpreter();
        }
    }
    
    /**
     * 乘法表达式
     * @Date 2022/11/5
     * @Author lifei
     */
    public class MultiplicationExpression implements Expression {
    
        private Expression expression1;
        private Expression expression2;
    
        public MultiplicationExpression(Expression expression1, Expression expression2) {
            this.expression1 = expression1;
            this.expression2 = expression2;
        }
    
        @Override
        public long interpreter() {
            return expression1.interpreter() * expression2.interpreter();
        }
    }
    
    /**
     * 除法表达式
     * @Date 2022/11/5
     * @Author lifei
     */
    public class DivisionExpression implements Expression {
    
        private Expression expression1;
        private Expression expression2;
    
        public DivisionExpression(Expression expression1, Expression expression2) {
            this.expression1 = expression1;
            this.expression2 = expression2;
        }
    
        @Override
        public long interpreter() {
            return expression1.interpreter() / expression2.interpreter();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    (2)示例二:监视器中的自定义警告规则
    /**
     * 自定义一个告警规则:
     * 1. 只包含“||、&&、>、<、==”这五个运算符;
     * 2. “>、<、==”运算符的优先级高于“||、&&”运算符,“&&”运算符优先级高于“||”
     * @Date 2022/11/5
     * @Author lifei
     */
    public class DemoTest {
    
        public static void main(String[] args) {
            String rule = "key1 > 100 && key2 < 30 || key3 < 100 || key4 == 88";
            AlertRuleInterpreter interpreter = new AlertRuleInterpreter(rule);
    
            Map<String, Long> state = new HashMap<>();
            state.put("key1", 101l);
            state.put("key3", 101l);
            state.put("key4", 81l);
    
            boolean alert = interpreter.interpreter(state);
            System.out.println(alert);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    表达式:

    public interface RuleExpression {
    
        boolean interpreter(Map<String, Long> state);
    }
    
    /**
     * 大于表达式
     * @Date 2022/11/5
     * @Author lifei
     */
    public class RuleGTExpression implements RuleExpression{
    
        private String key;
        private Long value;
    
        public RuleGTExpression(String expression) {
            String[] elements = expression.trim().split(" ");
            if (elements.length!=3 && !StringUtils.equals(elements[1], ">")) {
                throw new IllegalArgumentException("无效的表达式: " + expression);
            }
            this.key = elements[0];
            this.value = Long.parseLong(elements[2]);
        }
    
        @Override
        public boolean interpreter(Map<String, Long> state) {
            if (!state.containsKey(key)) {
                return false;
            }
            return state.get(key) > value;
        }
    }
    
    /**
     * 小于表达式
     * @Date 2022/11/5
     * @Author lifei
     */
    public class RuleLTExpression implements RuleExpression{
    
        private String key;
        private Long value;
    
        public RuleLTExpression(String expression) {
            String[] elements = expression.trim().split("\\s+");
            if (elements.length!=3 && !StringUtils.equals(elements[1], "<")) {
                throw new IllegalArgumentException("无效的表达式: " + expression);
            }
            this.key = elements[0];
            this.value = Long.parseLong(elements[2]);
        }
    
        @Override
        public boolean interpreter(Map<String, Long> state) {
            if (!state.containsKey(key)) {
                return false;
            }
            return state.get(key) < value;
        }
    }
    
    /**
     * 等于表达式
     * @Date 2022/11/5
     * @Author lifei
     */
    public class RuleEQExpression implements RuleExpression{
    
        private String key;
        private Long value;
    
        public RuleEQExpression(String expression) {
            String[] elements = expression.trim().split("\\s+");
            if (elements.length!=3 && !StringUtils.equals(elements[1], "==")) {
                throw new IllegalArgumentException("无效的表达式: " + expression);
            }
            this.key = elements[0];
            this.value = Long.parseLong(elements[2]);
        }
    
        @Override
        public boolean interpreter(Map<String, Long> state) {
            if (!state.containsKey(key)) {
                return false;
            }
            return state.get(key) == value;
        }
    }
    
    /**
     * && 表达式
     * @Date 2022/11/5
     * @Author lifei
     */
    public class RuleAndExpression implements RuleExpression{
    
        private List<RuleExpression> ruleExpressionList = new ArrayList<>();
    
        public RuleAndExpression(String expression) {
            String[] subExpressions = expression.trim().split("&&");
            for (String subExpression : subExpressions) {
                if (subExpression.contains(">")) {
                    ruleExpressionList.add(new RuleGTExpression(subExpression));
                } else if (subExpression.contains("<")) {
                    ruleExpressionList.add(new RuleLTExpression(subExpression));
                } else if (subExpression.contains("==")) {
                    ruleExpressionList.add(new RuleEQExpression(subExpression));
                } else {
                    throw new IllegalArgumentException("无效的表达式: " + expression);
                }
            }
        }
    
        @Override
        public boolean interpreter(Map<String, Long> state) {
            for (RuleExpression ruleExpression : ruleExpressionList) {
                if (!ruleExpression.interpreter(state)) {
                    return false;
                }
            }
            return true;
        }
    }
    
    /**
     * or 表达式
     * @Date 2022/11/5
     * @Author lifei
     */
    public class RuleORExpression implements RuleExpression{
    
        private List<RuleExpression> ruleExpressionList = new ArrayList<>();
    
        public RuleORExpression(String expression) {
            String[] subExpressions = expression.trim().split("\\|\\|");
            for (String subExpression : subExpressions) {
                ruleExpressionList.add(new RuleAndExpression(subExpression));
            }
        }
    
        @Override
        public boolean interpreter(Map<String, Long> state) {
            for (RuleExpression ruleExpression : ruleExpressionList) {
                if (ruleExpression.interpreter(state)) {
                    return true;
                }
            }
            return false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150

    应用表达式:

    /**
     * @Date 2022/11/5
     * @Author lifei
     */
    public class AlertRuleInterpreter {
    
        private RuleExpression ruleExpression;
    
        // key1 > 100 && key2 <1000 || key3 == 200
        public AlertRuleInterpreter(String ruleExpression) {
            this.ruleExpression = new RuleORExpression(ruleExpression);
        }
    
        public boolean interpreter(Map<String, Long> state) {
            return this.ruleExpression.interpreter(state);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3.3 命令模式

    命令模式可将“动作的请求者”从“动作的执行者”对象中解耦。比如,命令是遥控器,执行对象是厂商类。

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

    命令模式的主要作用和应用场景,是用来控制命令的执行,比如,异步、延迟、排队执行命令、撤销重做命令、存储命令、给命令记录日志等等

    策略模式和工厂模式的区别:

    策略模式包含策略的定义、创建和使用三部分。策略模式侧重“策略”或“算法”这个特定的应用场景,用来解决根据运行时状态从一组策略中选择不同策略的问题。

    工厂模式侧重封装对象的创建过程,这里的对象没有任何业务场景的限定,可以是策略,但也可以是其他东西。

    命令模式和工厂模式的区别:

    在策略模式中,不同的策略具有相同的目的、不同的实现、互相之间可以替换。比如,不同的排序算法可以相互替换。

    在命令模式中,不同的命令具有不同的目的,对应不同的处理逻辑,并且互相之间不可替换。

    示例一:遥控板上每个按钮都是一个命令
    (1)遥控板:
    /**
     * 遥控板上有多个按钮,每个按钮都对应一个命令
     * @Date 2022/11/5
     * @Author lifei
     */
    public class RemoteControl {
    
        // 启动按钮
        private Command[] onCommands;
        // 关闭按钮
        private Command[] offCommands;
    
        public RemoteControl() {
            int num = 7;
            // 定义两排按钮,七个启动开关的按钮,七个关闭的按钮
            this.onCommands = new Command[num];
            this.offCommands = new Command[num];
            // 对两排安妮进行初始化,初始化一个不做任何功能的
            NoCommand noCommand = new NoCommand();
            for (int i = 0; i < num; i++) {
                this.onCommands[i] = noCommand;
                this.offCommands[i] = noCommand;
            }
        }
    
        /**
         * 设置按钮功能
         * @param slot
         * @param onCommand
         * @param offCommand
         */
        public void setCommand(int slot, Command onCommand, Command offCommand) {
            this.onCommands[slot] = onCommand;
            this.offCommands[slot] = offCommand;
        }
    
        /**
         * 开启按钮是被按下
         * @param slot
         */
        public void onButtonWasPushed(int slot) {
            this.onCommands[slot].execute();
        }
    
        /**
         * 关闭按钮是被按下
         * @param slot
         */
        public void offButtonWasPushed(int slot) {
            this.offCommands[slot].execute();
        }
    
        /**
         * 打印遥控器功能
         * @return
         */
        @Override
        public String toString() {
            MoreObjects.ToStringHelper toStringHelper = MoreObjects.toStringHelper(RemoteControl.class);
            for (int i = 0; i < onCommands.length; i++) {
                toStringHelper.add("[slot " + i + "] " + onCommands[i].getClass().getName(), 
                        offCommands[i].getClass().getName());
            }
            return toStringHelper.toString();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    (2)实现命令
    public interface Command {
    
        void execute();
    }
    
    
    /**
     * 电灯,有开和关功能
     * @Date 2022/11/5
     * @Author lifei
     */
    public class Light {
    
        private String name;
    
        public Light(String name) {
            this.name = name;
        }
    
        public void on() {
            System.out.println(name + " 电灯打开");
        }
    
        public void off() {
            System.out.println(name + " 电灯关闭");
        }
    }
    
    /**
     * 关闭开关的命令
     * @Date 2022/11/5
     * @Author lifei
     */
    public class LightOffCommand implements Command {
    
        private Light light;
    
        public LightOffCommand(Light light) {
            this.light = light;
        }
    
        @Override
        public void execute() {
            this.light.off();
        }
    }
    
    /**
     * 电灯打开的命令
     * @Date 2022/11/5
     * @Author lifei
     */
    public class LightOnCommand implements Command {
    
        private Light light;
    
        public LightOnCommand(Light light) {
            this.light = light;
        }
    
        @Override
        public void execute() {
            light.on();
        }
    }
    
    /**
     * 音响
     * @Date 2022/11/5
     * @Author lifei
     */
    public class Stereo {
    
        private String name;
    
        public Stereo(String name) {
            this.name = name;
        }
    
        // 音量
        private int volume;
    
        public void on() {
            System.out.println(name + " 打开音响...");
        }
    
        public void setCD() {
            System.out.println(name + " 选择CD");
        }
    
        public void setVolume(int volume) {
            this.volume = volume;
            System.out.println(name + " 将音量设置为: " + volume);
        }
    
        public void off() {
            System.out.println("关闭音响");
        }
    }
    
    /**
     * @Date 2022/11/5
     * @Author lifei
     */
    public class StereoOffCommand implements Command {
    
        private Stereo stereo;
    
        public StereoOffCommand(Stereo stereo) {
            this.stereo = stereo;
        }
    
        @Override
        public void execute() {
            this.stereo.off();
        }
    }
    
    /**
     * 音响打开的命令
     * @Date 2022/11/5
     * @Author lifei
     */
    public class StereoOnWithCDCommand implements Command {
    
        private Stereo stereo;
    
        public StereoOnWithCDCommand(Stereo stereo) {
            this.stereo = stereo;
        }
    
        @Override
        public void execute() {
            this.stereo.on();
            this.stereo.setCD();
            this.stereo.setVolume(11);
        }
    }
    
    /**
     * 不做任何功能的按钮
     *  很多时候,空对象本身也被视为一种设计模式
     * @Date 2022/11/5
     * @Author lifei
     */
    public class NoCommand implements Command {
        @Override
        public void execute() {
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    (3)测试遥控器
    /**
     * @Date 2022/11/5
     * @Author lifei
     */
    public class ApplicationDemo {
    
        public static void main(String[] args) {
            RemoteControl remoteControl = new RemoteControl();
    
            Light livingRoomLight = new Light("客厅的电灯");
            Stereo stereo = new Stereo("大成音响");
    
            // 电灯命令
            LightOnCommand lightOnCommand = new LightOnCommand(livingRoomLight);
            LightOffCommand lightOffCommand = new LightOffCommand(livingRoomLight);
    
            // 音响命令
            StereoOnWithCDCommand stereoOnWithCDCommand = new StereoOnWithCDCommand(stereo);
            StereoOffCommand stereoOffCommand = new StereoOffCommand(stereo);
    
            // 设置命令
            remoteControl.setCommand(0, lightOnCommand, lightOffCommand);
            remoteControl.setCommand(1, stereoOnWithCDCommand, stereoOffCommand);
    
            // 打印遥控板
            System.out.println(remoteControl);
    
            // 按下按钮
            remoteControl.onButtonWasPushed(0);
            remoteControl.offButtonWasPushed(0);
    
            remoteControl.onButtonWasPushed(1);
            remoteControl.offButtonWasPushed(1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    示例二:添加撤销功能
    (1)改造命令接口,添加一个撤销功能
    public interface Command {
    
        void execute();
    
        // 添加一个撤销功能
        default void undo(){}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    (2)所有的命令实现都要添加一个撤销功能
    /**
     * 关闭开关的命令
     * @Date 2022/11/5
     * @Author lifei
     */
    public class LightOffCommand implements Command {
    
        private Light light;
    
        public LightOffCommand(Light light) {
            this.light = light;
        }
    
        @Override
        public void execute() {
            this.light.off();
        }
    
        @Override
        public void undo() {
            this.light.on();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    (3)遥控器上添加一个撤销按钮
    public class RemoteControl {
    
        // 启动按钮
        private Command[] onCommands;
        // 关闭按钮
        private Command[] offCommands;
        // 为遥控起添加一个撤销按钮
        private Command undoCommand;
    
        public RemoteControl() {
            int num = 7;
            // 定义两排按钮,七个启动开关的按钮,七个关闭的按钮
            this.onCommands = new Command[num];
            this.offCommands = new Command[num];
            // 对两排安妮进行初始化,初始化一个不做任何功能的
            NoCommand noCommand = new NoCommand();
            for (int i = 0; i < num; i++) {
                this.onCommands[i] = noCommand;
                this.offCommands[i] = noCommand;
            }
            // 撤销按钮初始化
            this.undoCommand = noCommand;
        }
    
        /**
         * 设置按钮功能
         * @param slot
         * @param onCommand
         * @param offCommand
         */
        public void setCommand(int slot, Command onCommand, Command offCommand) {
            this.onCommands[slot] = onCommand;
            this.offCommands[slot] = offCommand;
        }
    
        /**
         * 开启按钮是被按下
         * @param slot
         */
        public void onButtonWasPushed(int slot) {
            this.onCommands[slot].execute();
            this.undoCommand = this.onCommands[slot];
        }
    
        /**
         * 关闭按钮是被按下
         * @param slot
         */
        public void offButtonWasPushed(int slot) {
            this.offCommands[slot].execute();
            this.undoCommand = this.offCommands[slot];
        }
    
        /**
         * 按下撤销按钮
         */
        public void undoButtonWasPushed() {
            this.undoCommand.undo();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    (4)测试遥控器
    /**
     * @Date 2022/11/5
     * @Author lifei
     */
    public class ApplicationDemo {
    
        public static void main(String[] args) {
            RemoteControl remoteControl = new RemoteControl();
    
            Light livingRoomLight = new Light("客厅的电灯");
            Stereo stereo = new Stereo("大成音响");
    
            // 电灯命令
            LightOnCommand lightOnCommand = new LightOnCommand(livingRoomLight);
            LightOffCommand lightOffCommand = new LightOffCommand(livingRoomLight);
    
            // 音响命令
            StereoOnWithCDCommand stereoOnWithCDCommand = new StereoOnWithCDCommand(stereo);
            StereoOffCommand stereoOffCommand = new StereoOffCommand(stereo);
    
            // 设置命令
            remoteControl.setCommand(0, lightOnCommand, lightOffCommand);
            remoteControl.setCommand(1, stereoOnWithCDCommand, stereoOffCommand);
    
            // 打印遥控板
            System.out.println(remoteControl);
    
            // 按下按钮
            remoteControl.onButtonWasPushed(0);
            remoteControl.offButtonWasPushed(0);
            // 测试撤销按钮
            remoteControl.undoButtonWasPushed();
    
            remoteControl.onButtonWasPushed(1);
            remoteControl.offButtonWasPushed(1);
            // 测试撤销按钮
            remoteControl.undoButtonWasPushed();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    示例三:实现一个需要记录状态的撤销功能
    /**
     * 电扇命令
     * @Date 2022/11/5
     * @Author lifei
     */
    public class CeilingFanHighCommand implements Command {
        
        private CeilingFan ceilingFan;
        private int prevSpeed;
        
        public CeilingFanHighCommand(CeilingFan ceilingFan) {
            this.ceilingFan = ceilingFan;
        }
        
        @Override
        public void execute() {
            // 记录当前的速度,以便撤销的时候使用
            this.prevSpeed = ceilingFan.getSpeed();
            ceilingFan.high();
            System.out.println("设置成高档位");
        }
    
        @Override
        public void undo() {
            if (prevSpeed == CeilingFan.HIGH) {
                ceilingFan.high();
            } else if (prevSpeed == CeilingFan.MEDIUM) {
                ceilingFan.medium();
            } else if (prevSpeed == CeilingFan.LOW) {
                ceilingFan.low();
            } else if (prevSpeed == CeilingFan.OFF) {
                ceilingFan.off();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    3.4 迭代器模式

    迭代器模式(也叫游标模式):提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

    把游走的任务放在迭代器上,而不是聚合上。这样简化了聚合的接口和实现,也让责任各得各得其所。

    迭代器的实现类,通常以内部类的形式出现。

    (1)迭代器模式的示例

    不同的餐馆(晚餐菜单、煎饼屋菜单、咖啡馆菜单),通过实现java.util.Iterable接口中的iterator()方法,返回一个迭代器Iterator。通过迭代器,进行统一风格的菜单项遍历。Java5提供了for/in语法糖,可以直接对Iterable或数组进行 遍历。

    /**
     * 煎饼屋的菜单
     * @Date 2022/10/29
     * @Author lifei
     */
    public class PancakeHouseMenu implements Iterable<MeanItem> {
    
        private ArrayList<MeanItem> meanItems;
    
        public PancakeHouseMenu() {
            meanItems = new ArrayList<>();
            addItem("Pancake01", "001",  false, 2.99);
            addItem("Pancake02", "002",  true, 3.99);
            addItem("Pancake03", "003",  false, 1.99);
            addItem("Pancake04", "004",  true, 5.99);
        }
    
        public void addItem(String name, String description, boolean vegetarian, double price) {
            MeanItem meanItem = new MeanItem(name, description, vegetarian, price);
            meanItems.add(meanItem);
        }
    
        @Override
        public Iterator<MeanItem> iterator() {
            return new PancakeHouseMenuIterator(meanItems);
        }
    }
    
    /**
     * 晚餐菜单
     * 为了便利菜单,要返回一个迭代器,Iterable 里面定义了返回迭代器的方法
     * @Date 2022/10/29
     * @Author lifei
     */
    public class DinerMenu implements Iterable<MeanItem>{
    
        private static final int MAX_ITEMS = 6;
        private int numberOfItems = 0;
        private MeanItem[] meanItems;
    
        public DinerMenu() {
            this.meanItems = new MeanItem[MAX_ITEMS];
            addItem("Diner01", "001",  false, 2.99);
            addItem("Diner02", "002",  true, 3.99);
            addItem("Diner03", "003",  false, 1.99);
            addItem("Diner04", "004",  true, 5.99);
        }
    
        public void addItem(String name, String description, boolean vegetarian, double price) {
            MeanItem meanItem = new MeanItem(name, description, vegetarian, price);
            meanItems[numberOfItems++] = meanItem;
        }
    
        @Override
        public Iterator<MeanItem> iterator() {
            return new DinerMenuIterator(meanItems);
        }
    }
    
    /**
     * 咖啡菜单
     * @Date 2022/10/29
     * @Author lifei
     */
    public class CafeMenu implements Iterable<MeanItem> {
    
        private Map<String, MeanItem> meanItems = new HashMap<>();
    
        public CafeMenu() {
            addItem("Cafe01", "001", true, 5.31);
            addItem("Cafe02", "002", false, 1.31);
            addItem("Cafe03", "003", true, 2.31);
            addItem("Cafe04", "004", false, 3.31);
        }
    
        public void addItem(String name, String description, boolean vegetarian, double price) {
            MeanItem meanItem = new MeanItem(name, description, vegetarian, price);
            meanItems.put(name, meanItem);
        }
    
        @Override
        public Iterator<MeanItem> iterator() {
            return meanItems.values().iterator();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    菜单项:

    /**
     * 菜单项
     * @Date 2022/10/29
     * @Author lifei
     */
    public class MeanItem {
    
        private final String name;
        private final String description;
        private final boolean vegetarian;
        private final double price;
    
        public MeanItem(String name, String description, boolean vegetarian, double price) {
            this.name = name;
            this.description = description;
            this.vegetarian = vegetarian;
            this.price = price;
        }
    
        public String getName() {
            return name;
        }
    
        public String getDescription() {
            return description;
        }
    
        public boolean isVegetarian() {
            return vegetarian;
        }
    
        public double getPrice() {
            return price;
        }
    
        @Override
        public String toString() {
            return MoreObjects.toStringHelper(MeanItem.class)
                    .add("name", name)
                    .add("description", description)
                    .add("vegetarian", vegetarian)
                    .add("price", price)
                    .toString();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    服务员遍历菜单:

    /**
     * @Date 2022/10/29
     * @Author lifei
     */
    public class Waitress {
    
    //    private DinerMenu dinerMenu;
        private Iterable<MeanItem> dinerMenu;
    //    private PancakeHouseMenu pancakeHouseMenu;
        private Iterable<MeanItem> pancakeHouseMenu;
        private Iterable<MeanItem> cafeMenu;
    
        public Waitress(Iterable<MeanItem> dinerMenu, Iterable<MeanItem> pancakeHouseMenu,
                        Iterable<MeanItem> cafeMenu) {
            this.dinerMenu = dinerMenu;
            this.pancakeHouseMenu = pancakeHouseMenu;
            this.cafeMenu = cafeMenu;
        }
    
        public void printMenu() {
            // 煎饼屋菜单迭代器
            Iterator<MeanItem> pancakeIterator = pancakeHouseMenu.iterator();
            // 晚餐菜单迭代器
            Iterator<MeanItem> dinerIterator = dinerMenu.iterator();
            // 咖啡菜单
            Iterator<MeanItem> cafeIterator = cafeMenu.iterator();
            System.out.println("煎饼屋菜单......:");
            printMean(pancakeIterator);
            System.out.println("晚餐菜单......:");
            printMean(dinerIterator);
            System.out.println("咖啡菜单......");
            printMean(cafeIterator);
        }
    
        private void printMean(Iterator iterator) {
            while (iterator.hasNext()) {
                System.out.println(iterator.next());
            }
            // Java5 中包含了 新形式的for语句,称为for/in,底层基于迭代器实现。
            // 可以让你在一个集合或者一个数组中遍历,而且不需要显式的创建迭代器
            System.out.println("使用Java5的for/in 语法糖,遍历 cafeMean:");
            for (MeanItem menu : cafeMenu) {
                System.out.println(menu);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    运行迭代器示例:

    /**
     * 迭代器模式
     * @Date 2022/10/29
     * @Author lifei
     */
    public class ApplicationDemo {
    
        public static void main(String[] args) {
            Iterable<MeanItem> dinerMenu = new DinerMenu();
            Iterable<MeanItem> pancakeHouseMenu = new PancakeHouseMenu();
            Iterable<MeanItem> cafeMean = new CafeMenu();
            Waitress waitress = new Waitress(dinerMenu, pancakeHouseMenu, cafeMean);
            waitress.printMenu();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    (2)迭代器Iterator接口两种常见的定义
    // 接口定义方式一
    public interface Iterator<E> {
      boolean hasNext();
      void next();
      E currentItem();
    }
    
    // 接口定义方式二
    public interface Iterator<E> {
      boolean hasNext();
      E next();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    (3)ArrayList使用迭代器在遍历的时候,调用remove()方法会不会报错

    ArrayList使用迭代器在遍历的时候,调用remove方法会不会报错

    (4)支持快照的迭代器

    支持快照:迭代器被创建出来后,对list进行添加和删除操作,不影响已经生成的迭代器。

    思路一:创建迭代器的时候,拷贝一份数据;

    思路二:用快照时间,和创建时间,删除时间做对比;

    下面代码实现第二种思路:

    public interface List<E>  extends Iterable<E> {
    
        void add(E obj);
    
        void remove(E obj);
    }
    
    /**
     * 包含支持快照的迭代器:
     *  每个元素都有一个时间: addTime 和 delTime
     *     添加一个元素的时候: addTime 为当前时间, delTime 为 Long.MAX_VALUE
     *     删除一个元素的时候: delTime 修改为当前时间
     *     迭代遍历的时候,取: addTime< currentTime < delTime 的元素
     * @Date 2022/10/29
     * @Author lifei
     */
    public class ArrayList<E> implements List<E>{
    
        private static final int DEFAULT_CAPACITY = 10;
        private int actualSize; // 不包含删除标记元素
        private int totalSize; //  包含删除标记元素
    
        private E[] elements;
        private long[] addTimestamps;
        private long[] delTimestamps;
    
        public ArrayList() {
            this.elements = (E[])new Object[DEFAULT_CAPACITY];
            this.addTimestamps = new long[DEFAULT_CAPACITY];
            this.delTimestamps = new long[DEFAULT_CAPACITY];
            this.actualSize = 0;
            this.totalSize = 0;
        }
    
        @Override
        public void add(E obj) {
            elements[totalSize] = obj;
            addTimestamps[totalSize] = System.nanoTime();
            delTimestamps[totalSize] = Long.MAX_VALUE;
            totalSize++;
            actualSize++;
        }
    
        @Override
        public void remove(E obj) {
            for (int i = 0; i < totalSize; i++) {
                if (Objects.equals(elements[i], obj)) {
                    delTimestamps[i] = System.nanoTime();
                    actualSize--;
                }
            }
        }
    
        public int actualSize() {
            return this.actualSize;
        }
    
        public int totalSize() {
            return this.totalSize;
        }
    
        public E get(int i) {
            if (i>=totalSize) {
                throw new IndexOutOfBoundsException();
            }
            return elements[i];
        }
    
        public long getAddTimestamp(int i) {
            if (i >= totalSize) {
                throw new IndexOutOfBoundsException();
            }
            return addTimestamps[i];
        }
    
        public long getDelTimestamp(int i) {
            if (i>=totalSize) {
                throw new IndexOutOfBoundsException();
            }
            return delTimestamps[i];
        }
    
        @Override
        public Iterator<E> iterator() {
            return new SnapshotArrayIterator(this);
        }
    }
    
    /**
     * @Date 2022/10/30
     * @Author lifei
     */
    public class SnapshotArrayIterator<E> implements Iterator<E> {
    
        private long snapshotTimestamp;
        private int cursorInAll; // 在整个容器的下标,而非快照的下标
        private int leftCount; // 快照中还有几个元素未被遍历
        private ArrayList<E> list;
    
        public SnapshotArrayIterator(ArrayList<E> list) {
            this.snapshotTimestamp = System.nanoTime();
            this.list = list;
            this.leftCount = list.actualSize();
            this.cursorInAll = 0;
            justNext();
        }
        @Override
        public boolean hasNext() {
            return this.leftCount>0;
        }
    
        @Override
        public E next() {
            E currentItem = list.get(cursorInAll++);
            justNext();
            leftCount--;
            return currentItem;
        }
    
        private void justNext() {
            if (leftCount>0) {
                while (cursorInAll<list.totalSize()) {
                    if (snapshotTimestamp>list.getAddTimestamp(cursorInAll)
                            && snapshotTimestamp< list.getDelTimestamp(cursorInAll)) {
                        break;
                    }
                    cursorInAll++;
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131

    测试:

    /**
     * 测试支持快照的迭代器
     * @Date 2022/10/30
     * @Author lifei
     */
    public class ApplicationDemo {
    
        public static void main(String[] args) {
            ArrayList<Integer> list = new ArrayList<>();
            list.add(2);
            list.add(3);
            list.add(4);
            list.add(5);
            Iterator<Integer> iterator1 = list.iterator();
            list.remove(2);
            Iterator<Integer> iterator2 = list.iterator();
    
            showIterator(iterator1);
            showIterator(iterator2);
        }
    
        private static void showIterator(Iterator<Integer> iterator) {
            while (iterator.hasNext()) {
                System.out.print(iterator.next() + ", ");
            }
            System.out.println();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    3.5 中介者模式

    中介者模式:中介模式定义了一个单独的(中介)对象,来封装一组对象之间的交互。将这组对象之间的交互委派给与中介对象交互,来避免对象之间的直接交互。

    中介模式的设计思想跟中间层很像,通过引入中介这个中间层,将一组对象之间的交互关系(或者说依赖关系)从多对多(网状关系)转换为一对多(星状关系)。

    在使用中介模式的时候,我们要根据实际的情况,平衡对象之间交互的复杂度和中介类本身的复杂度。

    中介者模式和观察者模式的区别:

    在观察者模式中,交互关系往往都是单向的,一个参与者要么是观察者,要么是被观察者,不会兼具两种身份。

    中介模式中,交互关系错综复杂,除此之外,还能进行顺序控制。

    如果一个参与者状态的改变,其他参与者执行的操作有一定先后顺序的要求,这个时候,中介模式就可以利用中介类,通过先后调用不同参与者的方法,来实现顺序的控制,而观察者模式是无法实现这样的顺序要求的。

    3.6 观察者模式(发布订阅模式)

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

    (1)观察者模式(自己实现)

    主题抽象:三个经典方法

    /**
     * 主题: 注册观察者、移除观察者,通知观察者
     * @Date 2022/10/21
     * @Author lifei
     */
    public interface Subject {
        void registerObserver(Observer observer);
    
        void removeObserver(Observer observer);
    
        // 当主题状态改变的时候,这个方法会被调用,以通知所有的观察者
        void notifyObservers();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    观察者抽象:有一个更新状态的方法

    /**
     * 观察者:当主题状态发生变化的时候,依赖该主题的观察者会自动更新
     * @Date 2022/10/21
     * @Author lifei
     */
    public interface Observer {
        void update(float temp, float humidity, float pressure);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    观察者的公共接口:

    /**
     *  观察者自己的行为方法
     * @Date 2022/10/21
     * @Author lifei
     */
    public interface DisplayElement {
    
        void display();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    主题的实现:

    /**
     * 一个天气数据主题
     * @Date 2022/10/22
     * @Author lifei
     */
    public class WeatherDataSubject implements Subject {
        private List<Observer> observerList = new ArrayList<>();
        private float temperature;
        private float humidity;
        private float pressure;
    
        @Override
        public void registerObserver(Observer observer) {
            observerList.add(observer);
        }
    
        @Override
        public void removeObserver(Observer observer) {
            int i = observerList.indexOf(observer);
            if (i>=0) {
                observerList.remove(i);
            }
        }
    
        @Override
        public void notifyObservers() {
            for (Observer observer : observerList) {
                observer.update(temperature, humidity, pressure);
            }
        }
    
        /**
         * 改变主题的状态,并通知观察者
         * @param temperature
         * @param humidity
         * @param pressure
         */
        public void setMeasurements(float temperature, float humidity, float pressure) {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            measurementsChanged();
        }
    
        /**
         * 通知观察者
         */
        private void measurementsChanged() {
            notifyObservers();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    一个观察者实现:

    /**
     * 一个观察者实现: 通过构造函数把自己注册进一个主题
     * @Date 2022/10/22
     * @Author lifei
     */
    public class CurrentConditionsDisplayObserver implements Observer, DisplayElement {
    
        private Subject weatherData;
        private float temperature;
        private float humidity;
    
        // 通过构造函数,把自己注册进一个主题
        public CurrentConditionsDisplayObserver(Subject subject) {
            this.weatherData = subject;
            subject.registerObserver(this);
        }
    
        @Override
        public void display() {
            System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
        }
    
        @Override
        public void update(float temp, float humidity, float pressure) {
            this.temperature = temp;
            this.humidity = humidity;
            display();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    (2)JDK自带的观察者模式

    可观察者:

    /**
     * 可观察者
     * 继承 java.util.Observable
     * @Date 2022/10/22
     * @Author lifei
     */
    public class WeatherDataObservable extends Observable {
    
        private float temperature;
        private float humidity;
        private float pressure;
    
        public void setMeasureMents(float temperature, float humidity, float pressure) {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            measurementsChanged();
        }
    
        /**
         * 调用 notifyObservers() 之前,要先调用setChanged() 来指示状态已经改变
         * notifyObservers() 有一个重载方法 notifyObservers(args)
         */
        public void measurementsChanged() {
            // setChanged() 方法用来标记状态已经改变的事实,好让notifyObservers() 知道当它被调用时应该更新观察者。
            // 如果调用notifyObservers() 之前没有先调用 setChanged(), 观察者就不会被通知
            setChanged();
            // 不传递参数,观察者就需要从可观察者对象中"拉"(pull)数据
            notifyObservers();
            //如果传递参数,就是推送数据给观察者
    //        Object args = new float[]{temperature, humidity, pressure};
    //        notifyObservers(args);
        }
    
        // 观察者会利用下面三个方法获取WeatherData对象的状态
        public float getTemperature() {
            return temperature;
        }
    
        public float getHumidity() {
            return humidity;
        }
    
        public float getPressure() {
            return pressure;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    观察者:

    下面是观察者,从可观察者拉取数据的例子。

    注意:

    • 可观察者是一个类,这限制了
    /**
     * 观察者
     * 实现java.util.Observer
     * @Date 2022/10/22
     * @Author lifei
     */
    public class CurrentConditionsDisplay implements Observer, DisplayElement {
    
        private Observable observable;
    
        private float temperature;
        private float humidity;
    
        public CurrentConditionsDisplay(Observable observable) {
            this.observable = observable;
            observable.addObserver(this);
        }
    
        @Override
        public void update(Observable o, Object arg) {
            if (o instanceof WeatherDataObservable) {
                WeatherDataObservable weatherDataObservable = (WeatherDataObservable) o;
                this.temperature = weatherDataObservable.getTemperature();
                this.humidity = weatherDataObservable.getHumidity();
                display();
            }
        }
    
        @Override
        public void display() {
            System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    public class WeatherStation {
    
        public static void main(String[] args) {
            // 可观察者
            WeatherDataObservable weatherDataObservable = new WeatherDataObservable();
            // 观者者
            java.util.Observer observer1 = new CurrentConditionsDisplay(weatherDataObservable);
            // 改变可观察者的状态
            weatherDataObservable.setMeasureMents(20.1f, 0.3f, 105.1f);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    (3)Guava的EventBus

    动手实现一个EventBus

    当调用Eventbus.post(obj)发送数据的时候,和接收消息的类型是obj类型的父类型的观察者方法会被触发。

    当我们调用 post() 函数发送消息的时候,并非把消息发送给所有的观察者,而是发送给可匹配的观察者。所谓可匹配指的是,能接收的消息类型是发送消息(post 函数定义中的 event)类型的父类

    AObserver 能接收的消息类型是 XMsg,BObserver 能接收的消息类型是 YMsg,CObserver 能接收的消息类型是 ZMsg。其中,XMsg 是 YMsg 的父类。当我们如下发送消息的时候,相应能接收到消息的可匹配观察者如下所示:

    
    XMsg xMsg = new XMsg();
    YMsg yMsg = new YMsg();
    ZMsg zMsg = new ZMsg();
    post(xMsg); => AObserver接收到消息
    post(yMsg); => AObserverBObserver接收到消息
    post(zMsg); => CObserver接收到消息
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    创建一个主题:

    /**
     * 一个主题
     * @Date 2022/10/22
     * @Author lifei
     */
    public class WeatherDataEvent {
    
        private float temperature;
        private float humidity;
        private float pressure;
    
        public void setMeasurements(float temperature, float humidity, float pressure) {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
        }
    
        public float getTemperature() {
            return temperature;
        }
    
        public float getHumidity() {
            return humidity;
        }
    
        public float getPressure() {
            return pressure;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    创建一个观察者:

    /**
     * 一个观察者:使用了Guava的@Subscribe 注解
     * @Date 2022/10/22
     * @Author lifei
     */
    public class CurrentConditionsDisplayListener{
    
        /**
         * 添加一个订阅主题的竹梅
         */
        @Subscribe
        public void display(WeatherDataEvent weatherDataEvent) {
            System.out.println("Current conditions: " + weatherDataEvent.getTemperature() + "F degrees and " + weatherDataEvent.getHumidity() + "% humidity");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    使用通过EventBus串通:

    public class WeatherStation {
    
        public static void main(String[] args) {
    
            // 定义一个EventBus
    //        EventBus eventBus = new EventBus(); // 同步阻塞模式
            final int DEFAULT_EVENTBUS_THREAD_POOL_SIZE = 20; // 异步非阻塞线程池大小
            // 异步非阻塞的方式
            // 异步非阻塞的方式
            ExecutorService executorService = Executors.newFixedThreadPool(DEFAULT_EVENTBUS_THREAD_POOL_SIZE);
            EventBus eventBus = new AsyncEventBus(executorService);
    
            // 注册一个观察者
            eventBus.register(new CurrentConditionsDisplayListener());
    
            // 创建一个主题
            WeatherDataEvent weatherDataEvent = new WeatherDataEvent();
            weatherDataEvent.setMeasurements(20.1f, 0.3f, 105.1f);
            // 发布主题(会通知观察者), post里传递的是观察者接收的数据,
            eventBus.post(weatherDataEvent);
            // 关闭线程池
            executorService.shutdown();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    @Subscribe注解所在的方法参数,可以是任意Object类型(不能是基本数据类型)。

    public class CurrentConditionsDisplayListener{
    
        /**
         * 添加一个订阅主题的竹梅
         */
        @Subscribe
        public void display(WeatherDataEvent weatherDataEvent) {
            System.out.println("Current conditions: " + weatherDataEvent.getTemperature() + "F degrees and "
                    + weatherDataEvent.getHumidity() + "% humidity");
        }
    
        
        @Subscribe
        public void display(Float temperature) {
            System.out.println("Current conditions: " + temperature + "F degrees and "
                    + 0.3 + "% humidity");
        }
    }
    
    
    public class WeatherStation {
    
        public static void main(String[] args) {
            // 定义一个EventBus
    //        EventBus eventBus = new EventBus(); // 同步阻塞模式
            final int DEFAULT_EVENTBUS_THREAD_POOL_SIZE = 20; // 异步非阻塞线程池大小
            // 异步非阻塞的方式
            ExecutorService executorService = Executors.newFixedThreadPool(DEFAULT_EVENTBUS_THREAD_POOL_SIZE);
            EventBus eventBus = new AsyncEventBus(executorService);
    
            // 注册一个观察者
            eventBus.register(new CurrentConditionsDisplayListener());
    
            // 创建一个主题
            WeatherDataEvent weatherDataEvent = new WeatherDataEvent();
            weatherDataEvent.setMeasurements(20.1f, 0.3f, 105.1f);
            // 发布主题(会通知观察者)
    //        eventBus.post(weatherDataEvent);
            eventBus.post(weatherDataEvent.getTemperature());
            // 关闭线程池
            executorService.shutdown();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    3.7 备忘录模式

    主要用来防丢失、撤销、恢复等。

    备忘录模式:在不违背封装原则的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便之后恢复对象为先前的状态.

    要点一:存储副本以便后期恢复;要点二:不违背封装原则。

    备忘录模式和备份的区别:备忘录模式更侧重于代码的设计和实现,备份更侧重架构设计或产品设计。

    大对象的备份(备份占用的存储空间会比较大,备份和恢复的耗时会比较长),常见的处理办法:只备份必要的恢复信息,结合最新的数据来恢复;再比如,全量备份和增量备份相结合,低频全量备份,高频增量备份,两者结合来做恢复。

    示例一:撤销上一次输入
    (1)版本一:违背了封装原则
    /**
     * 当前的文本内容
     * @Date 2022/11/1
     * @Author lifei
     */
    public class InputText {
    
        private StringBuilder text = new StringBuilder();
    
        public String getText() {
            return text.toString();
        }
    
        public void append(String input) {
            text.append(input);
        }
    
        public void setText(String text) {
            this.text.replace(0, this.text.length(), text);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    之前的备份:

    /**
     * 历史内容备份
     * @Date 2022/11/1
     * @Author lifei
     */
    public class SnapshotHolder {
    
        private Stack<InputText> snapshots = new Stack<>();
    
        public InputText popSnapShot() {
            return snapshots.pop();
        }
    
        public void pushSnapshot(InputText inputText) {
            InputText deepClonedInputText = new InputText();
            deepClonedInputText.setText(inputText.getText());
            snapshots.push(deepClonedInputText);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    应用:

    /**
     * 应用
     * @Date 2022/11/1
     * @Author lifei
     */
    public class ApplicationMain {
    
        public static void main(String[] args) {
            InputText inputText = new InputText();
            SnapshotHolder snapshotHolder = new SnapshotHolder();
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNext()) {
                String input = scanner.next();
                if (StringUtils.equalsIgnoreCase(input, ":list")) {
                    System.out.println(inputText.getText());
                }else if (StringUtils.equalsIgnoreCase(input, ":undo")) {
                    InputText snapShot = snapshotHolder.popSnapShot();
                    inputText.setText(snapShot.getText());
                }else {
                    snapshotHolder.pushSnapshot(inputText);
                    inputText.append(input);
                }
    
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    上面的存在的问题:

    • InputText的set() 方法可能被其它地方利用,违背封装原则;
    • 快照理论上不应该被修改;
    (2)版本二:使用备忘录模式进行改造

    一个单独的快照类

    /**
     * 一个快照类
     * @Date 2022/11/2
     * @Author lifei
     */
    public class Snapshot {
    
        private final String text;
        public Snapshot(String text) {
            this.text = text;
        }
    
        public String getText() {
            return text;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    通过InputText创建快照,或者根据快照更新内容:

    /**
     * 输入的内容
     * @Date 2022/11/2
     * @Author lifei
     */
    public class InputText {
    
        private StringBuilder text = new StringBuilder();
    
        public void append(String input) {
            text.append(input);
        }
      
        public String getText() {
            return text.toString();
        }
    
        public Snapshot createSnapshot() {
            return new Snapshot(text.toString());
        }
    
        public void restoreSnapshot(Snapshot snapshot) {
            text.replace(0, text.length(), snapshot.getText());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    快照持有者:

    /**
     * 快照的持有者
     * @Date 2022/11/2
     * @Author lifei
     */
    public class SnapshotHolder {
    
        private Stack<Snapshot> snapshots = new Stack<>();
    
        public Snapshot popSnapshot() {
            return snapshots.pop();
        }
    
        public void pushSnapshot(Snapshot snapshot) {
            this.snapshots.push(snapshot);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    应用:

    /**
     * 应用
     * @Date 2022/11/2
     * @Author lifei
     */
    public class ApplicationMain {
    
        public static void main(String[] args) {
            SnapshotHolder snapshotHolder = new SnapshotHolder();
            InputText inputText = new InputText();
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNext()) {
                String input = scanner.next();
                if (StringUtils.equalsIgnoreCase(input, ":list")) {
                    System.out.println(inputText.getText());
                }else if (StringUtils.equalsIgnoreCase(input, ":undo")) {
                    inputText.restoreSnapshot(snapshotHolder.popSnapshot());
                }else {
                    snapshotHolder.pushSnapshot(inputText.createSnapshot());
                    inputText.append(input);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3.8 模版方法模式

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

    这里的算法,可以理解为广义的“业务逻辑”。算法骨架就是模版,包含算法骨架的方法就是“模版方法”。

    模版方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现。

    模版方法模式是为了解决复用和扩展两个问题。

    模版方法模式的应用:

    • 复用:Java InputStream、Java AbstractList
    • 扩展:Java HttpServlet的service() 方法就是一个模版方法、TestCase

    模版方法模式和回调函数:

    • 从应用场景来看:同步回调跟模版方法模式几乎一样。异步回调跟模版方法模式有较大差别,更像是观察者模式;
    • 从代码实现上看:回调基于组合关系来实现。模版方法模式基于继承来实现;

    组合优于继承。

    (1)示例一:一个带有钩子的模版:
    /**
     * 定义一个带有钩子的模版方法
     * @Date 2022/10/23
     * @Author lifei
     */
    public abstract class CaffeineBeverageWithHook {
    
        /**
         * 模版方法
         */
        public void prepareRecipe() {
            boilWater(); // 烧水
            brew(); // 冲泡
            pourInCup(); // 倒入杯中
            // 由钩子方法决定是否添加配料
            if (customerWantsCondiments()) {
                addCondiments(); // 添加配料
            }
        }
        
        public abstract void brew();
        
        public abstract void addCondiments();
        
        public void boilWater() {
            System.out.println("烧水.....");
        }
        
        public void pourInCup() {
            System.out.println("倒入被中......");
        }
    
        /**
         * 钩子方法,由子类决定是否覆盖
         * @return
         */
        public boolean customerWantsCondiments() {
            return true;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    实现:

    /**
     * 模版方法模式:子类
     * @Date 2022/10/23
     * @Author lifei
     */
    public class CoffeeWithHook extends CaffeineBeverageWithHook {
        @Override
        public void brew() {
            out.println("冲泡咖啡");
        }
    
        @Override
        public void addCondiments() {
            out.println("添加 牛奶");
        }
    
        /**
         * 实现钩子方法
         * @return
         */
        @Override
        public boolean customerWantsCondiments() {
            String answer = getUserInput();
            if (StringUtils.startsWithIgnoreCase(answer, "y")) {
                return true;
            }else {
                return false;
            }
        }
    
        /**
         * 获取用户输入
         * @return
         */
        private String getUserInput() {
            String answer = null;
            out.println("你想添加牛奶配料吗?");
            try (InputStreamReader inputStreamReader = new InputStreamReader(in);
            BufferedReader reader = new BufferedReader(inputStreamReader)) {
                answer = reader.readLine();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            if (answer==null) {
                return "no";
            }else {
                return answer;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    /**
     *  模版方法,示例
     * @Date 2022/10/23
     * @Author lifei
     */
    public class TemplateMain {
    
        public static void main(String[] args) {
            CaffeineBeverageWithHook coffee = new CoffeeWithHook();
            coffee.prepareRecipe();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.9 状态模式

    状态模式:允许对象(context)在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

    context(上下文)是一个类,他可以拥有一些内部状态,第一个示例中,GumballMachine 就是context。在状态模式中,context的行为随时委托到那些状态对象中的一个。随着时间的流逝,当前状态在状态对象集合中游走改变,以反映出context内部的状态,因此,context的行为也会跟着改变。但是context的客户对于状态对象了解不多,甚至根本是浑然不觉。

    状态模式是状态机的一种实现方式。状态机又叫有限状态机,它有3部分组成:状态、事件、动作。其中,事件被称为转移条件。

    状态模式,将事件触发的状态转移和动作执行,拆分到不同的状态类中。

    (1)第一个示例
    版本一:没有使用状态
    /**
     * 糖果售货机
     * @Date 2022/10/25
     * @Author lifei
     */
    public class GumballMachine {
    
        // 售罄
        private final static int SOLD_OUT = 0;
        // 没有25分钱
        private final static int NO_QUARTER = 1;
        //有25分
        private final static int HAS_QUARTER = 2;
        // 售出糖果
        private final static int SOLD = 3;
    
        private int state = SOLD_OUT;
    
        private int count;
        public GumballMachine(int count) {
            this.count = count;
            if (count>0) {
                state = NO_QUARTER;
            }
        }
    
        /**
         * 投入硬币
         */
        public void insertQuarter() {
            if (state == HAS_QUARTER) { //已经有硬币了
                System.out.println("你不用投入另一个硬币");
            } else if (state == SOLD_OUT) { // 售罄
                System.out.println("你不能投入硬币,因为这个机器的糖果销售完了");
            } else if (state == SOLD) {
                System.out.println("请等待,我们将给你一个糖果");
            } else if (state == NO_QUARTER) {
                state = HAS_QUARTER;
                System.out.println("你投入了一个硬币");
            }
        }
    
        /**
         * 退回硬币
         */
        public void ejectQuarter() {
            if (state == HAS_QUARTER) {
                System.out.println("硬币退回");
                state = NO_QUARTER;
            } else if (state == NO_QUARTER) {
                System.out.println("你还没有投入硬币");
            } else if (state == SOLD) {
                System.out.println("糖果已经销售给你了");
            } else if (state == SOLD_OUT) {
                System.out.println("不能退,因为你没有投入硬币");
            }
        }
    
        /**
         * 转动曲柄
         */
        public void turnCrank() {
            if (state == SOLD) {
                System.out.println("转动两次,不能给你另一个糖果");
            } else if (state == NO_QUARTER) {
                System.out.println("你转动了曲柄,但是你还没有投入硬币");
            } else if (state == SOLD_OUT) {
                System.out.println("你转动了曲柄,但是这里没有糖果");
            } else if (state == HAS_QUARTER) {
                System.out.println("你转动了......");
                state = SOLD;
                dispense();
            }
        }
    
        /**
         * 发放糖果
         */
        private void dispense() {
            if (state == SOLD) {
                System.out.println("你个糖果是弹出");
                count = count-1;
                if (count==0) {
                    System.out.println("售罄了!");
                    state = SOLD_OUT;
                } else {
                    state = NO_QUARTER;
                }
            } else if (state == NO_QUARTER) {
                System.out.println("你需要先付费!");
            } else if (state == SOLD_OUT) {
                System.out.println("没有糖果可以弹出");
            } else if (state == HAS_QUARTER) {
                System.out.println("没有糖果售出");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97

    测试:

    /**
     * 测试状态模式
     * @Date 2022/10/25
     * @Author lifei
     */
    public class GumballMachineTestDrive {
    
        public static void main(String[] args) {
            GumballMachine gumballMachine = new GumballMachine(5);
    
            gumballMachine.insertQuarter();
            gumballMachine.turnCrank();
    
            gumballMachine.insertQuarter();
            gumballMachine.ejectQuarter();
            gumballMachine.turnCrank();
    
            gumballMachine.insertQuarter();
            gumballMachine.turnCrank();
            gumballMachine.insertQuarter();
            gumballMachine.turnCrank();
            gumballMachine.ejectQuarter();
    
            gumballMachine.insertQuarter();
            gumballMachine.insertQuarter();
            gumballMachine.turnCrank();
            gumballMachine.insertQuarter();
            gumballMachine.turnCrank();
            gumballMachine.insertQuarter();
            gumballMachine.turnCrank();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    版本二:使用状态模式进行改造

    定义状态,状态里面带有行为:

    /**
     * 糖果售卖机的状态
     */
    public interface GumballMachineState {
    
        // 投入硬币
        void insertQuarter();
    
        // 退出硬币
        void ejectQuarter();
    
        // 转动手柄
        void turnCrank();
    
        // 售卖糖果
        void dispense();
    }
    
    /**
     * 售罄的状态
     * @Date 2022/10/25
     * @Author lifei
     */
    public class GumballMachineSoldOutState implements GumballMachineState{
    
        private GumballMachine gumballMachine;
    
        public GumballMachineSoldOutState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }
    
        @Override
        public void insertQuarter() {
            System.out.println("已经售罄,不能投入硬币");
        }
    
        @Override
        public void ejectQuarter() {
            System.out.println("已经售罄,没有投入硬币!");
        }
    
        @Override
        public void turnCrank() {
            System.out.println("你又转动了转轴,已经售罄了!");
        }
    
        @Override
        public void dispense() {
            System.out.println("已经售罄了,不能售出糖果");
        }
    }
    
    /**
     * 没有硬币的状态
     * @Date 2022/10/25
     * @Author lifei
     */
    public class GumballMachineNoQuarterState implements GumballMachineState{
    
        private GumballMachine gumballMachine;
    
        public GumballMachineNoQuarterState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }
    
        @Override
        public void insertQuarter() {
            System.out.println("你投入了一枚硬币.......");
            gumballMachine.setGumballMachineState(gumballMachine.getHasQuarterState());
        }
    
        @Override
        public void ejectQuarter() {
            System.out.println("还没有投入硬币......");
        }
    
        @Override
        public void turnCrank() {
            System.out.println("已经转动转轴,但是还没有投入硬币......");
        }
    
        @Override
        public void dispense() {
            System.out.println("你需要先投入硬币....");
        }
    }
    
    /**
     * 已经投币的状态
     * @Date 2022/10/25
     * @Author lifei
     */
    public class GumballMachineHasQuarterState implements GumballMachineState{
    
        private Random randomWinner = new Random(System.currentTimeMillis());
    
        private GumballMachine gumballMachine;
    
        public GumballMachineHasQuarterState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }
    
        @Override
        public void insertQuarter() {
            System.out.println("你已经投过硬币了......");
        }
    
        @Override
        public void ejectQuarter() {
            System.out.println("退出投入的硬币....");
            this.gumballMachine.setGumballMachineState(gumballMachine.getNoQuarterState());
        }
    
        @Override
        public void turnCrank() {
            System.out.println("转动了转轴....");
            int winner = randomWinner.nextInt(10);
            if (winner==0 && gumballMachine.getCount()>1) {
                System.out.println("恭喜,获奖了!");
                this.gumballMachine.setGumballMachineState(gumballMachine.getWinnerState());
            } else {
                this.gumballMachine.setGumballMachineState(gumballMachine.getSoldState());
            }
        }
    
        @Override
        public void dispense() {
            System.out.println("请转动转轴.....");
        }
    }
    
    /**
     * 销售的状态
     * @Date 2022/10/25
     * @Author lifei
     */
    public class GumballMachineSoldState implements GumballMachineState{
    
        private GumballMachine gumballMachine;
    
        public GumballMachineSoldState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }
    
        @Override
        public void insertQuarter() {
            System.out.println("硬币已经投过了,不需要再次投入硬币。请等待,我们将给你一个糖果!");
        }
    
        @Override
        public void ejectQuarter() {
            System.out.println("不能退出硬币,应为你已经转动了转轴!");
        }
    
        @Override
        public void turnCrank() {
            System.out.println("你又转动了转轴,但是不会产生更多的糖果......");
        }
    
        @Override
        public void dispense() {
            gumballMachine.releaseBall();
            if (gumballMachine.getCount()==0) {
                System.out.println("哦,售罄了!");
                gumballMachine.setGumballMachineState(gumballMachine.getSoldOutState());
            } else {
                gumballMachine.setGumballMachineState(gumballMachine.getNoQuarterState());
            }
        }
    }
    
    /**
     * 售罄的状态
     * @Date 2022/10/25
     * @Author lifei
     */
    public class GumballMachineWinnerState implements GumballMachineState{
    
        private GumballMachine gumballMachine;
    
        public GumballMachineWinnerState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }
    
        @Override
        public void insertQuarter() {
            System.out.println("你已经中奖了,不需要投入硬币,我们即将给你糖果");
        }
    
        @Override
        public void ejectQuarter() {
            System.out.println("你已经中奖了,即将给你糖果,但是不能退出硬币给你。");
        }
    
        @Override
        public void turnCrank() {
            System.out.println("你转动了转轴,但是不会给你更多糖果。请稍等,会把奖励的糖果给你。");
        }
    
        @Override
        public void dispense() {
            System.out.println("你是获奖者,你能得到两个糖果");
            gumballMachine.releaseBall();
            if (gumballMachine.getCount() == 0) {
                System.out.println("抱歉,售罄了,不能给你第二个糖果");
                gumballMachine.setGumballMachineState(gumballMachine.getSoldOutState());
            } else {
                System.out.println("哇!给你第二个糖果");
                gumballMachine.releaseBall();
                if (gumballMachine.getCount()==0) {
                    System.out.println("售罄了!");
                    gumballMachine.setGumballMachineState(gumballMachine.getSoldOutState());
                } else {
                    gumballMachine.setGumballMachineState(gumballMachine.getNoQuarterState());
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218

    糖果机器,使用这些状态:

    /**
     * 糖果收获机器
     * @Date 2022/10/25
     * @Author lifei
     */
    public class GumballMachine {
    
        // 售罄状态
        private GumballMachineState soldOutState;
        // 没有投币状态
        private GumballMachineState noQuarterState;
        // 已经投币状体
        private GumballMachineState hasQuarterState;
        // 销售状态
        private GumballMachineState soldState;
        // 获奖状态
        private GumballMachineState winnerState;
    
        // 初始状态设置为 售罄状态
        private GumballMachineState gumballMachineState;
        private int count;
    
        public GumballMachine(int count) {
            this.soldOutState = new GumballMachineSoldOutState(this);
            this.noQuarterState = new GumballMachineNoQuarterState(this);
            this.hasQuarterState = new GumballMachineHasQuarterState(this);
            this.soldState = new GumballMachineSoldState(this);
            this.winnerState = new GumballMachineWinnerState(this);
            this.count = count;
            if (count>0) {
                gumballMachineState = this.noQuarterState;
            } else {
                gumballMachineState = this.soldOutState;
            }
        }
    
        public void insertQuarter() {
            gumballMachineState.insertQuarter();
        }
    
        public void ejectQuarter() {
            gumballMachineState.ejectQuarter();
        }
    
        public void turnCrank() {
            gumballMachineState.turnCrank();
            gumballMachineState.dispense();
        }
    
        public GumballMachineState getGumballMachineState() {
            return gumballMachineState;
        }
    
        public void setGumballMachineState(GumballMachineState gumballMachineState) {
            this.gumballMachineState = gumballMachineState;
        }
    
        public GumballMachineState getSoldOutState() {
            return soldOutState;
        }
    
        public GumballMachineState getNoQuarterState() {
            return noQuarterState;
        }
    
        public GumballMachineState getHasQuarterState() {
            return hasQuarterState;
        }
    
        public GumballMachineState getSoldState() {
            return soldState;
        }
    
        public GumballMachineState getWinnerState() {
            return winnerState;
        }
    
        public int getCount() {
            return count;
        }
    
        /**
         * 释放一个糖果
         */
        public void releaseBall() {
            System.out.println("一个糖果是滚出了售货机!");
            if (count!=0) {
                count -= 1;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91

    测试:

    /**
     * 状态模式测试
     * @Date 2022/10/25
     * @Author lifei
     */
    public class GumballMachineTestDrive {
    
        public static void main(String[] args) {
            GumballMachine gumballMachine = new GumballMachine(5);
    
            gumballMachine.insertQuarter();
            gumballMachine.turnCrank();
    
            gumballMachine.insertQuarter();
            gumballMachine.turnCrank();
            gumballMachine.insertQuarter();
            gumballMachine.turnCrank();
            
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    (2)第二个示例:超级马里奥游戏
    版本一:分支逻辑法

    逻辑判断较多,不好维护。

    /**
     * 马里奥的状态
     * @Date 2022/10/25
     * @Author lifei
     */
    public enum MarioState {
    
        SMALL(0), // 小马里奥
        SUPER(1), // 超级马里奥
        FIRE(2), // 火焰马里奥
        CAPE(3) // 斗篷马里奥
        ;
        private int value;
    
        MarioState(int value) {
            this.value = value;
        }
    
        public int getValue() {
            return value;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    /**
     * 马里奥 状态机: 分支逻辑法
     * @Date 2022/10/25
     * @Author lifei
     */
    public class MarioStateMachine {
    
        private int score;
        private MarioState currentState;
    
        public MarioStateMachine() {
            this.score = 0;
            this.currentState = SMALL;
        }
    
        /**
         * 获得蘑菇,变成超级 super, 并加100积分
         */
        public void obtainMushRoom() {
            if (Objects.equals(currentState,SMALL)) {
                this.score += 100;
                this.currentState = SUPER;
            }
        }
    
        /**
         * 获得斗篷,加200积分,变身 斗篷马里奥
         */
        public void obtainCape() {
            if (Objects.equals(currentState,SMALL) || Objects.equals(currentState , SUPER)) {
                this.currentState = CAPE;
                this.score += 200;
            }
        }
    
        /**
         * 获得火焰,+300分, 变成火焰马里奥
         */
        public void obtainFireFlower() {
            if (Objects.equals(currentState,SMALL) || Objects.equals(currentState,SUPER)) {
                this.currentState = FIRE;
                this.score += 300;
            }
        }
    
        /**
         * 遇到怪兽
         */
        public void meetMonster() {
            if (Objects.equals(currentState,CAPE)) {
                this.score -= 200;
                this.currentState = SMALL;
            } else if (Objects.equals(currentState,SUPER)) {
                this.score -= 100;
                this.currentState = SMALL;
            } else if (Objects.equals(currentState , FIRE)) {
                this.score -= 300;
                this.currentState = SMALL;
            }
        }
    
        public int getScore() {
            return score;
        }
    
        public MarioState getCurrentState() {
            return currentState;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    版本二:查表法

    使用“状态*行为”形成的二维表表示状态的转移。

    当操作比较简单的时候,可以使用查表法。

    /**
     * 定义行为
     * @Date 2022/10/26
     * @Author lifei
     */
    public enum MarioEvent {
    
        GOT_MUSHROOM(0),
        GOT_CAPE(1),
        GOT_FIRE(2),
        MET_MONSTER(3),
        ;
    
        private int value;
    
        MarioEvent(int value) {
            this.value = value;
        }
    
        public int getValue() {
            return value;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    /**
     * 马里奥 状态机: 查表法
     * @Date 2022/10/25
     * @Author lifei
     */
    public class MarioStateMachine02 {
    
        private int score;
        private MarioState currentState;
    
        // 行号是 MarioState.value, 列号是 MarioEvent.value
        private static final MarioState[][] transitionTable = {
                // SMALL: GOT_MUSHROOM ,GOT_CAPE ,GOT_FIRE ,MET_MONSTER
                {SUPER, CAPE, FIRE, SMALL},
                // SUPER: GOT_MUSHROOM ,GOT_CAPE ,GOT_FIRE ,MET_MONSTER
                {SUPER, CAPE, FIRE, SMALL},
                // FIRE: GOT_MUSHROOM ,GOT_CAPE ,GOT_FIRE ,MET_MONSTER
                {FIRE, FIRE, FIRE, SMALL},
                // CAPE: GOT_MUSHROOM ,GOT_CAPE ,GOT_FIRE ,MET_MONSTER
                {CAPE, CAPE, CAPE, SMALL},
        };
    
        private static final int[][] actionTable = {
                // SMALL: GOT_MUSHROOM ,GOT_CAPE ,GOT_FIRE ,MET_MONSTER
                {+100, +200, +300, +0},
                // SUPER: GOT_MUSHROOM ,GOT_CAPE ,GOT_FIRE ,MET_MONSTER
                {+0, +200, +300, -100},
                // FIRE: GOT_MUSHROOM ,GOT_CAPE ,GOT_FIRE ,MET_MONSTER
                {+0, +0, +0, -300},
                // CAPE: GOT_MUSHROOM ,GOT_CAPE ,GOT_FIRE ,MET_MONSTER
                {+0, +0, +0, -200},
        };
    
        public MarioStateMachine02() {
            this.score = 0;
            this.currentState = SMALL;
        }
    
        /**
         * 获得蘑菇,变成超级 super, 并加100积分
         */
        public void obtainMushRoom() {
            executeEvent(GOT_MUSHROOM);
        }
    
        /**
         * 获得斗篷,加200积分,变身 斗篷马里奥
         */
        public void obtainCape() {
            executeEvent(GOT_CAPE);
        }
    
        /**
         * 获得火焰,+300分, 变成火焰马里奥
         */
        public void obtainFireFlower() {
            executeEvent(GOT_FIRE);
        }
    
        /**
         * 遇到怪兽
         */
        public void meetMonster() {
            executeEvent(MET_MONSTER);
        }
    
        private void executeEvent(MarioEvent event) {
            int stateRow = currentState.getValue();
            int eventRow = event.getValue();
            this.currentState = transitionTable[stateRow][eventRow];
            this.score = actionTable[stateRow][eventRow];
        }
    
        public int getScore() {
            return score;
        }
    
        public MarioState getCurrentState() {
            return currentState;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    版本三:状态模式

    完整代码

    当涉及到复杂的操作,就需要用到状态模式了。

    /**
     * 所有状态类的接口
     * @Date 2022/10/27
     * @Author lifei
     */
    public interface IMario {
        // 当前状态的名称
        MarioState getName();
        // 以下是定义的事件
        void obtainMushRoom();
        void obtainCape();
        void obtainFireFlower();
        void meetMonster();
    }
    
    /**
     * @Date 2022/10/27
     * @Author lifei
     */
    public class SmallMario implements IMario{
    
        private MarioStateMachine03 marioStateMachine;
    
        public SmallMario(MarioStateMachine03 marioStateMachine) {
            this.marioStateMachine = marioStateMachine;
        }
    
        @Override
        public MarioState getName() {
            return MarioState.SMALL;
        }
    
        @Override
        public void obtainMushRoom() {
            marioStateMachine.setMarioState(marioStateMachine.getSuperState());
            marioStateMachine.setScore(marioStateMachine.getScore() + 100);
        }
    
        @Override
        public void obtainCape() {
            marioStateMachine.setMarioState(marioStateMachine.getCapeState());
            marioStateMachine.setScore(marioStateMachine.getScore() + 200);
        }
    
        @Override
        public void obtainFireFlower() {
            marioStateMachine.setMarioState(marioStateMachine.getFireFlowerState());
            marioStateMachine.setScore(marioStateMachine.getScore() + 300);
        }
    
        @Override
        public void meetMonster() {
            // 什么也不做
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    /**
     * 状态模式的状态机
     * @Date 2022/10/27
     * @Author lifei
     */
    public class MarioStateMachine03 {
    
        private IMario smallState;
        private IMario superState;
        private IMario capeState;
        private IMario fireFlowerState;
    
        private IMario marioState;
        private int score;
    
        public MarioStateMachine03() {
            this.smallState = new SmallMario(this);
            this.superState = new SuperMario(this);
            this.capeState  = new CapeMario(this);
            this.fireFlowerState = new FireFlowerMario(this);
            this.marioState = smallState;
        }
    
        public MarioState getCurrentState() {
            return marioState.getName();
        }
    
        public IMario getMarioState() {
            return marioState;
        }
    
        public void setMarioState(IMario marioState) {
            this.marioState = marioState;
        }
    
        public IMario getSmallState() {
            return smallState;
        }
    
        public IMario getSuperState() {
            return superState;
        }
    
        public IMario getCapeState() {
            return capeState;
        }
    
        public IMario getFireFlowerState() {
            return fireFlowerState;
        }
    
        public int getScore() {
            return this.score;
        }
    
        public void setScore(int score) {
            this.score = score;
        }
    
        public void obtainMushRoom() {
            marioState.obtainMushRoom();
        }
    
        public void obtainCape() {
            marioState.obtainCape();
        }
    
        public void obtainFireFlower() {
            marioState.obtainFireFlower();
        }
        public void meetMonster() {
            marioState.meetMonster();
        }
    
        @Override
        public String toString() {
            return MoreObjects.toStringHelper(MarioStateMachine03.class)
                    .add("marioState", marioState)
                    .add("score", score)
                    .toString();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    结合单例模式进行改造:

    public interface IMario {
        MarioState getName();
    
        // 以下是定义的事件
        void obtainMushRoom(MarioStateMachine04 marioStateMachine);
        void obtainCape(MarioStateMachine04 marioStateMachine);
        void obtainFireFlower(MarioStateMachine04 marioStateMachine);
        void meetMonster(MarioStateMachine04 marioStateMachine);
    }
    
    public class SmallMario implements IMario {
    
        private static final SmallMario instance = new SmallMario();
        private SmallMario(){}
    
        public static SmallMario getInstance() {
            return instance;
        }
    
        @Override
        public MarioState getName() {
            return MarioState.SMALL;
        }
    
        @Override
        public void obtainMushRoom(MarioStateMachine04 marioStateMachine) {
            marioStateMachine.setMarioState(SuperMario.getInstance());
            marioStateMachine.setScore(marioStateMachine.getScore() + 100);
        }
    
        @Override
        public void obtainCape(MarioStateMachine04 marioStateMachine) {
            marioStateMachine.setMarioState(CapeMario.getInstance());
            marioStateMachine.setScore(marioStateMachine.getScore() + 200);
        }
    
        @Override
        public void obtainFireFlower(MarioStateMachine04 marioStateMachine) {
            marioStateMachine.setMarioState(FireFlowerMario.getInstance());
            marioStateMachine.setScore(marioStateMachine.getScore() + 300);
        }
    
        @Override
        public void meetMonster(MarioStateMachine04 marioStateMachine) {
            // 什么也不做
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    public class MarioStateMachine04 {
    
        private IMario marioState;
        private int score;
    
        public MarioStateMachine04() {
            this.score = 0;
            this.marioState = SmallMario.getInstance();
        }
    
        public MarioState getCurrentState() {
            return marioState.getName();
        }
    
        public IMario getMarioState() {
            return marioState;
        }
    
        public void setMarioState(IMario marioState) {
            this.marioState = marioState;
        }
    
        public int getScore() {
            return this.score;
        }
    
        public void setScore(int score) {
            this.score = score;
        }
    
        public void obtainMushRoom() {
            marioState.obtainMushRoom(this);
        }
    
        public void obtainCape() {
            marioState.obtainCape(this);
        }
    
        public void obtainFireFlower() {
            marioState.obtainFireFlower(this);
        }
        public void meetMonster() {
            marioState.meetMonster(this);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    3.10 策略模式

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

    (1)示例一:策略模式的体现

    定义一个算法族:

    /**
     * 一个飞的行为
     * @Date 2022/10/23
     * @Author lifei
     */
    public interface FlyBehavior {
        void fly();
    }
    
    /**
     * 一个具体fly的行为
     * @Date 2022/10/23
     * @Author lifei
     */
    public class FlyNoWay implements FlyBehavior{
        @Override
        public void fly() {
            System.out.println("FlyNoWay: fly...0");
        }
    }
    
    /**
     * 一个具体的行为
     * @Date 2022/10/23
     * @Author lifei
     */
    public class FlyWithWings implements FlyBehavior{
        @Override
        public void fly() {
            System.out.println("FlyWithWings: fly 1,2,3");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    使用策略:

    /**
     * @Date 2022/10/23
     * @Author lifei
     */
    public abstract class Duck {
    
        protected FlyBehavior flyBehavior;
    
        public void performFly() {
            flyBehavior.fly();
        }
    
        public void setFlyBehavior(FlyBehavior flyBehavior) {
            this.flyBehavior = flyBehavior;
        }
    }
    
    /**
     * @Date 2022/10/23
     * @Author lifei
     */
    public class MallardDuck extends Duck{
    
        public MallardDuck() {
            this.flyBehavior = new FlyNoWay();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    测试:

    public class StrategyMain {
    
        public static void main(String[] args) {
            Duck duck = new MallardDuck();
            duck.performFly();
            duck.setFlyBehavior(new FlyWithWings());
            duck.performFly();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    (2)示例二:对一个文件内容进行排序的代码演进
    第一版:为使用设计模式之前
    /**
     * 文件排序
     * @Date 2022/10/23
     * @Author lifei
     */
    public class FileSorter {
    
        private static final long GB = 1024 * 1024 * 1024;
    
        public void sort(String filePath) {
            // 省略校验逻辑
            File file = new File(filePath);
            long fileSize = file.length();
            if (fileSize < 6 * GB) {
                quickSort(filePath);
            } else if (fileSize < 10 * GB) {
                externalSort(filePath);
            } else if (fileSize < 100 * GB) {
                concurrentExternalSort(filePath);
            } else {
                mapReduceSort(filePath);
            }
        }
    
        private void mapReduceSort(String filePath) {
            System.out.println("当文件超级大的时候,使用真正的Map-Reduce排序");
        }
    
        private void concurrentExternalSort(String filePath) {
            System.out.println("当文件过大当时候,使用并发当外部排序");
        }
    
        private void externalSort(String filePath) {
            System.out.println("当文件比较大当时候,使用外部排序");
        }
    
        private void quickSort(String filePath) {
            System.out.println("当文件不是很大当时候,使用快速排序");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    第二版:定义出排序算法族(将策略的定义分离出来)
    public interface ISortAlg {
    
        void sort(String filePath);
    }
    
    public class QuickSort implements ISortAlg{
        @Override
        public void sort(String filePath) {
            System.out.println("当文件不是很大当时候,使用快速排序");
        }
    }
    
    public class ExternalSort implements ISortAlg{
        @Override
        public void sort(String filePath) {
            System.out.println("当文件比较大当时候,使用外部排序");
        }
    }
    
    public class ConcurrentExternalSort implements ISortAlg{
        @Override
        public void sort(String filePath) {
            System.out.println("当文件过大当时候,使用并发当外部排序");
        }
    }
    
    public class MapReduceSort implements ISortAlg{
        @Override
        public void sort(String filePath) {
            System.out.println("当文件超级大的时候,使用真正的Map-Reduce排序");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    使用:

    public class FileSorter {
    
        private static final long GB = 1024 * 1024 * 1024;
    
        public void sort(String filePath) {
            // 省略校验逻辑
            File file = new File(filePath);
            long fileSize = file.length();
            ISortAlg sortAlg;
            if (fileSize < 6 * GB) {
                sortAlg = new QuickSort();
            } else if (fileSize < 10 * GB) {
                sortAlg = new ExternalSort();
            } else if (fileSize < 100 * GB) {
                sortAlg = new ConcurrentExternalSort();
            } else {
                sortAlg = new MapReduceSort();
            }
            sortAlg.sort(filePath);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    第三版:使用工厂模式对算法进行封装
    /**
     * 算法的工厂模式
     * @Date 2022/10/23
     * @Author lifei
     */
    public class SortAlgFactory {
    
        private static final Map<String, ISortAlg> algs = new HashMap<>();
    
        static {
            algs.put("QuickSort", new QuickSort());
            algs.put("ExternalSort", new ExternalSort());
            algs.put("ConcurrentExternalSort", new ConcurrentExternalSort());
            algs.put("MapReduceSort", new MapReduceSort());
        }
    
        public static ISortAlg getSortAlg(String type) {
            if (StringUtils.isBlank(type)) {
                throw new IllegalArgumentException("类型不能为空");
            }
            return algs.get(type);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    public class FileSorter {
    
        private static final long GB = 1024 * 1024 * 1024;
    
        public void sort(String filePath) {
            // 省略校验逻辑
            File file = new File(filePath);
            long fileSize = file.length();
            ISortAlg sortAlg;
            if (fileSize < 6 * GB) {
                sortAlg = SortAlgFactory.getSortAlg("QuickSort");
            } else if (fileSize < 10 * GB) {
                sortAlg = SortAlgFactory.getSortAlg("ExternalSort");
            } else if (fileSize < 100 * GB) {
                sortAlg = SortAlgFactory.getSortAlg("ConcurrentExternalSort");
            } else {
                sortAlg = SortAlgFactory.getSortAlg("MapReduceSort");
            }
            sortAlg.sort(filePath);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    第四版:借助查表法,去除if-else判断
    public class SortAlgRange {
    
        private final Range<Long> range;
        private final ISortAlg sortAlg;
    
        public SortAlgRange(Range<Long> range, ISortAlg sortAlg) {
            this.range = range;
            this.sortAlg = sortAlg;
        }
    
        public boolean isRange(long size) {
            return range.contains(size);
        }
    
        public ISortAlg getSortAlg() {
            return sortAlg;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    public class SortAlgRangeFactory {
    
        private static final long GB = 1024 * 1024 * 1024;
    
        private static final List<SortAlgRange> sortAlgRanges = new ArrayList<>();
    
        static {
            sortAlgRanges.add(new SortAlgRange(Range.<Long>closed(0l, 6*GB), new QuickSort()));
            sortAlgRanges.add(new SortAlgRange(Range.<Long>openClosed(6*GB, 10 * GB), new ExternalSort()));
            sortAlgRanges.add(new SortAlgRange(Range.<Long>openClosed(10 * GB, 100 * GB), new ConcurrentExternalSort()));
            sortAlgRanges.add(new SortAlgRange(Range.<Long>greaterThan(100 * GB), new MapReduceSort()));
        }
    
        public static ISortAlg getSortAlg(long size) {
            for (SortAlgRange sortAlgRange : sortAlgRanges) {
                if (sortAlgRange.isRange(size)) {
                    return sortAlgRange.getSortAlg();
                }
            }
            return sortAlgRanges.get(sortAlgRanges.size()-1).getSortAlg();
        }
    
        public static void main(String[] args) {
            for (SortAlgRange sortAlgRange : sortAlgRanges) {
                System.out.println(sortAlgRange);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    public class FileSorter {
    
        private static final long GB = 1024 * 1024 * 1024;
    
        public void sort(String filePath) {
            // 省略校验逻辑
            File file = new File(filePath);
            long fileSize = file.length();
            ISortAlg sortAlg;
            sortAlg = SortAlgRangeFactory.getSortAlg(fileSize);
            sortAlg.sort(filePath);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3.11 访问者模式

    访问者模式:允许一个或多个操作应用到一组对象上,解耦操作和对象本身。

    函数重载在大部分面向对象编程语言中是静态绑定的。也就是说,调用类的哪个重载函数,是在编译期间,由参数的声明类型决定的,而非运行时,根据参数的实际类型决定的。

    (1)访问者模式的演变示例:提取不同类型文件内容信息到txt文件
    版本一:不同子类负责不同的功能
    /**
     * 资源文件的抽象
     * @Date 2022/10/30
     * @Author lifei
     */
    public abstract class ResourceFile {
    
        protected String filePath;
    
        public ResourceFile(String filePath) {
            this.filePath = filePath;
        }
    
        // 提取文件内容到txt文件
        public abstract void extract2txt();
    }
    
    /**
     * 提取word文件内容到txt
     * @Date 2022/10/30
     * @Author lifei
     */
    public class WordFile extends ResourceFile{
    
        public WordFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public void extract2txt() {
            System.out.println("提取Word文件内容到txt文件");
        }
    }
    
    /**
     * 提取pdf文件内容到txt
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PdfFile extends ResourceFile{
    
        public PdfFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public void extract2txt() {
            System.out.println("提取Pdf文件内容到txt");
        }
    }
    
    /**
     * 抽取PPT文件内容到txt
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PPTFile extends ResourceFile{
    
        public PPTFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public void extract2txt() {
            System.out.println("提取PPT文件内容......");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    测试:

    /**
     * 测试
     * @Date 2022/10/30
     * @Author lifei
     */
    public class ToolApplication {
    
        public static void main(String[] args) {
            List<ResourceFile> resourceFiles = listAllResourceFiles();
            for (ResourceFile resourceFile : resourceFiles) {
                resourceFile.extract2txt();
            }
        }
    
        private static List<ResourceFile> listAllResourceFiles() {
            List<ResourceFile> result = new ArrayList<>();
            result.add(new PdfFile("a.pdf"));
            result.add(new WordFile("b.docx"));
            result.add(new PPTFile("c.pptx"));
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    版本二:业务操作跟具体数据结构解耦,利用重载

    数据结构:

    /**
     * 资源文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public abstract class ResourceFile {
        protected final String filePath;
    
        public ResourceFile(String filePath) {
            this.filePath = filePath;
        }
    
        public String getFilePath() {
            return filePath;
        }
    }
    
    /**
     * PDF文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PdfFile extends ResourceFile{
        public PdfFile(String filePath) {
            super(filePath);
        }
    }
    
    /**
     * PPT 文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PPTFile extends ResourceFile{
        public PPTFile(String filePath) {
            super(filePath);
        }
    }
    
    /**
     * word 文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public class WordFile extends ResourceFile{
        public WordFile(String filePath) {
            super(filePath);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    行为:

    /**
     * 提取功能: 使用函数的重载
     * @Date 2022/10/30
     * @Author lifei
     */
    public class Extractor {
    
        public void extract2txt(PdfFile pdfFile) {
            System.out.println("提取PDF 文件内容....");
        }
    
        public void extract2txt(PPTFile pptFile) {
            System.out.println("提取PPT文件内容......");
        }
    
        public void extract2txt(WordFile wordFile) {
            System.out.println("提取word文件内容.....");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    应用: 编译不通过

    /**
     * 测试:行为和数据结构分离
     *   多态是一种动态绑定,可以在运行的时候获取对象的实际类型,来运行实际类型对应的方法。
     *   而函数重载是一种静态绑定,是在编译期间,由参数的声明类型决定的,而非运行时,根据参数的实际类型决定的。
     * @Date 2022/10/30
     * @Author lifei
     */
    public class ToolApplication {
    
        public static void main(String[] args) {
            Extractor extractor = new Extractor();
            List<ResourceFile> resourceFiles = listAllResourceFiles();
            for (ResourceFile resourceFile : resourceFiles) {
                // 利用函数重载,下面这句话编译不能通过
                extractor.extract2txt(resourceFile);
            }
        }
        private static List<ResourceFile> listAllResourceFiles() {
            List<ResourceFile> result = new ArrayList<>();
            result.add(new PdfFile("a.pdf"));
            result.add(new WordFile("b.docx"));
            result.add(new PPTFile("c.pptx"));
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    版本三:向访问者模式跨出重要一步

    资源文件

    /**
     * 资源文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public abstract class ResourceFile {
        protected String filePath;
        public ResourceFile(String filePath) {
            this.filePath = filePath;
        }
    
        public abstract void accept(Extractor extractor);
    }
    
    /**
     * PDF文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PdfFile extends ResourceFile{
        public PdfFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public void accept(Extractor extractor) {
            extractor.extract2txt(this);
        }
    }
    
    /**
     * PPT文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PPTFile extends ResourceFile{
        public PPTFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public void accept(Extractor extractor) {
            extractor.extract2txt(this);
        }
    }
    
    /**
     * word文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public class WordFile extends ResourceFile{
        public WordFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public void accept(Extractor extractor) {
            extractor.extract2txt(this);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    行为:

    /**
     * 提取功能: 使用函数的重载
     * @Date 2022/10/30
     * @Author lifei
     */
    public class Extractor {
    
        public void extract2txt(PdfFile pdfFile) {
            System.out.println("提取PDF 文件内容....");
        }
    
        public void extract2txt(PPTFile pptFile) {
            System.out.println("提取PPT文件内容......");
        }
    
        public void extract2txt(WordFile wordFile) {
            System.out.println("提取word文件内容.....");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    应用:

    /**
     * 使用访问者模式
     * @Date 2022/10/30
     * @Author lifei
     */
    public class ToolApplication {
    
        public static void main(String[] args) {
            Extractor extractor = new Extractor();
            List<ResourceFile> resourceFiles = listAllResourceFiles();
            for (ResourceFile resourceFile : resourceFiles) {
                resourceFile.accept(extractor);
            }
        }
        private static List<ResourceFile> listAllResourceFiles() {
            List<ResourceFile> result = new ArrayList<>();
            result.add(new PdfFile("a.pdf"));
            result.add(new WordFile("b.docx"));
            result.add(new PPTFile("c.pptx"));
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    这个时候,如果添加新功鞥,仍然需要修改每个资源文件,违反了开闭原则。比如:添加一个压缩功能

    /**
     * 压缩功能
     * @Date 2022/10/30
     * @Author lifei
     */
    public class Compressor {
    
        public void compressor(PdfFile pdfFile) {
            System.out.println("压缩pdf...");
        }
    
        public void compressor(PPTFile pdfFile) {
            System.out.println("压缩PPT...");
        }
    
        public void compressor(WordFile pdfFile) {
            System.out.println("压缩word...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    修改所有的资源文件:

    /**
     * 资源文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public abstract class ResourceFile {
        protected String filePath;
        public ResourceFile(String filePath) {
            this.filePath = filePath;
        }
    
        public abstract void accept(Extractor extractor);
    
        public abstract void accept(Compressor compressor);
    }
    
    /**
     * PDF文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PdfFile extends ResourceFile{
        public PdfFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public void accept(Extractor extractor) {
            extractor.extract2txt(this);
        }
    
        @Override
        public void accept(Compressor compressor) {
            compressor.compressor(this);
        }
    }
    
    /**
     * PPT文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PPTFile extends ResourceFile{
        public PPTFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public void accept(Extractor extractor) {
            extractor.extract2txt(this);
        }
    
        @Override
        public void accept(Compressor compressor) {
            compressor.compressor(this);
        }
    }
    
    /**
     * word文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public class WordFile extends ResourceFile{
        public WordFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public void accept(Extractor extractor) {
            extractor.extract2txt(this);
        }
    
        @Override
        public void accept(Compressor compressor) {
            compressor.compressor(this);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    应用:

    /**
     * 使用访问者模式
     * @Date 2022/10/30
     * @Author lifei
     */
    public class ToolApplication {
    
        public static void main(String[] args) {
            Extractor extractor = new Extractor();
            Compressor compressor = new Compressor();
            List<ResourceFile> resourceFiles = listAllResourceFiles();
            for (ResourceFile resourceFile : resourceFiles) {
                // 执行下面这行代码的时候,会根据多台调用实际类型的accept函数
                resourceFile.accept(extractor);
                resourceFile.accept(compressor);
            }
        }
        private static List<ResourceFile> listAllResourceFiles() {
            List<ResourceFile> result = new ArrayList<>();
            result.add(new PdfFile("a.pdf"));
            result.add(new WordFile("b.docx"));
            result.add(new PPTFile("c.pptx"));
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    版本四:将行为进行抽象出Visitor,完成访问者模式

    行为抽象:visitor

    public interface Visitor {
        void visitor(PdfFile pdfFile);
        void visitor(PPTFile pptFile);
        void visitor(WordFile wordFile);
    }
    
    /**
     * 压缩功能
     * @Date 2022/10/30
     * @Author lifei
     */
    public class Compressor implements Visitor{
    
        @Override
        public void visitor(PdfFile pdfFile) {
            System.out.println("压缩pdf...");
        }
    
        @Override
        public void visitor(PPTFile pdfFile) {
            System.out.println("压缩PPT...");
        }
    
        @Override
        public void visitor(WordFile pdfFile) {
            System.out.println("压缩word...");
        }
    }
    
    /**
     * 提取功能: 使用函数的重载
     * @Date 2022/10/30
     * @Author lifei
     */
    public class Extractor implements Visitor{
    
        @Override
        public void visitor(PdfFile pdfFile) {
            System.out.println("提取PDF 文件内容....");
        }
    
        @Override
        public void visitor(PPTFile pptFile) {
            System.out.println("提取PPT文件内容......");
        }
    
        @Override
        public void visitor(WordFile wordFile) {
            System.out.println("提取word文件内容.....");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    数据结构:

    /**
     * 资源文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public abstract class ResourceFile {
        protected String filePath;
        public ResourceFile(String filePath) {
            this.filePath = filePath;
        }
    
        public abstract void accept(Visitor visitor);
    
    }
    
    /**
     * PDF文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PdfFile extends ResourceFile {
        public PdfFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visitor(this);
        }
    }
    
    /**
     * PPT文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PPTFile extends ResourceFile {
        public PPTFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visitor(this);
        }
    }
    
    /**
     * word文件
     * @Date 2022/10/30
     * @Author lifei
     */
    public class WordFile extends ResourceFile {
        public WordFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public void accept(Visitor visitor) {
            visitor.visitor(this);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    应用:

    /**
     * 使用访问者模式
     * @Date 2022/10/30
     * @Author lifei
     */
    public class ToolApplication {
    
        public static void main(String[] args) {
            Extractor extractor = new Extractor();
            Compressor compressor = new Compressor();
            List<ResourceFile> resourceFiles = listAllResourceFiles();
            for (ResourceFile resourceFile : resourceFiles) {
                // 执行下面这行代码的时候,会根据多台调用实际类型的accept函数
                resourceFile.accept(extractor);
                resourceFile.accept(compressor);
            }
        }
        private static List<ResourceFile> listAllResourceFiles() {
            List<ResourceFile> result = new ArrayList<>();
            result.add(new PdfFile("a.pdf"));
            result.add(new WordFile("b.docx"));
            result.add(new PPTFile("c.pptx"));
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    (2)Single Dispatch 和 Double Dispatch

    所谓 Single Dispatch,指的是执行哪个对象的方法,根据对象的运行时类型来决定;执行对象的哪个方法,根据方法参数的编译时类型来决定。所谓 Double Dispatch,指的是执行哪个对象的方法,根据对象的运行时类型来决定;执行对象的哪个方法,根据方法参数的运行时类型来决定。

    具体到编程语言的语法机制,Single Dispatch 和 Double Dispatch 跟多态和函数重载直接相关。当前主流的面向对象编程语言(比如,Java、C++、C#)都只支持 Single Dispatch,不支持 Double Dispatch。

    因此 支持双分派的语言不需要访问者模式。

    /**
     * 父类
     * @Date 2022/10/30
     * @Author lifei
     */
    public class ParentClass {
    
        public void f() {
            System.out.println("I'm ParentClass's f() ");
        }
    }
    
    /**
     * @Date 2022/10/30
     * @Author lifei
     */
    public class ChildClass extends ParentClass{
    
        @Override
        public void f() {
            System.out.println("I'm ChildClass's f()");
        }
    }
    
    /**
     * 验证单分工
     * @Date 2022/10/30
     * @Author lifei
     */
    public class SingleDispatchClass {
    
        public void polymorphismFunction(ParentClass p) {
            p.f();
        }
    
        public void overloadFunction(ParentClass p) {
    //        p.f();
            System.out.println("I am overloadFunction(ParentClass p).");
        }
    
        public void overloadFunction(ChildClass c) {
    //        c.f();
            System.out.println("I am overloadFunction(ChildClass c).");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    (3)使用工厂模式实现案例:提取不同类型文件内容信息到txt文件

    数据结构:

    /**
     * @Date 2022/10/30
     * @Author lifei
     */
    public abstract class ResourceFile {
    
        private String filePath;
    
        public ResourceFile(String filePath) {
            this.filePath = filePath;
        }
    
        public String getFilePath() {
            return filePath;
        }
    
        public abstract ResourceFileType getType();
    }
    
    
    /**
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PdfFile extends ResourceFile{
        public PdfFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public ResourceFileType getType() {
            return ResourceFileType.PDF;
        }
    }
    
    /**
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PPTFile extends ResourceFile{
        public PPTFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public ResourceFileType getType() {
            return ResourceFileType.PPT;
        }
    }
    
    /**
     * @Date 2022/10/30
     * @Author lifei
     */
    public class WordFile extends ResourceFile{
        public WordFile(String filePath) {
            super(filePath);
        }
    
        @Override
        public ResourceFileType getType() {
            return ResourceFileType.WORD;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    行为:

    /**
     * @Date 2022/10/30
     * @Author lifei
     */
    public interface Extractor {
    
        void extract2txt(ResourceFile resourceFile);
    }
    
    /**
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PDFExtractor implements Extractor{
        @Override
        public void extract2txt(ResourceFile resourceFile) {
            System.out.println("提取PDF文件内容......");
        }
    }
    
    /**
     * @Date 2022/10/30
     * @Author lifei
     */
    public class PPTExtractor implements Extractor{
        @Override
        public void extract2txt(ResourceFile resourceFile) {
            System.out.println("提取PPT文件内容......");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    工厂:

    /**
     * @Date 2022/10/30
     * @Author lifei
     */
    public class ExtractorFactory {
        private static final Map<ResourceFileType, Extractor> extractors = new HashMap<>();
        static {
            extractors.put(ResourceFileType.PDF, new PDFExtractor());
            extractors.put(ResourceFileType.PPT, new PPTExtractor());
            extractors.put(ResourceFileType.WORD, new WordExtractor());
        }
    
        public static Extractor getExtractor(ResourceFileType type) {
            return extractors.get(type);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    应用:

    /**
     * @Date 2022/10/30
     * @Author lifei
     */
    public class ApplicationDemo {
    
        public static void main(String[] args) {
            List<ResourceFile> resourceFiles = listAllResourceFiles();
            for (ResourceFile resourceFile : resourceFiles) {
                Extractor extractor = ExtractorFactory.getExtractor(resourceFile.getType());
                extractor.extract2txt(resourceFile);
            }
        }
    
        private static List<ResourceFile> listAllResourceFiles() {
            List<ResourceFile> result = new ArrayList<>();
            result.add(new PdfFile("a.pdf"));
            result.add(new WordFile("b.docx"));
            result.add(new PPTFile("c.pptx"));
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    vue中对axios的二次封装和节流与防抖
    PD虚拟机(Parallels Desktop)2024mac苹果电脑19免费版下载
    [项目管理-27]:任务的目的,背后的原因是任务实施首要思考的问题。
    Compositional Minimax Optimization学习之路
    .NET周刊【7月第2期 2023-07-09】
    PCB layout 小功率板子减小干扰方法
    MySQL数据库之多表查询
    NET微服务架构CI/CD自动构建Jenkins+Gitee
    泰勒级数、海森矩阵、雅可比矩阵
    力扣 428. 序列化和反序列化 N 叉树 DFS
  • 原文地址:https://blog.csdn.net/hefrankeleyn/article/details/127710890