设计模式-Java

设计原则(SOLID)

  1. 单一职责原则Single Responsibility Principle):一个类只负责一项职责。
  2. 开闭原则Open Closed Principle):对扩展开放,对修改关闭。
  3. 里氏替换原则Liskov Substitution Principle):子类对象能够替换父类对象使用,而不影响程序的正确性。
  4. 迪米特法则Law of Demeter):一个对象应该对其他对象有尽可能少的了解。
  5. 接口隔离原则Interface Segregation Principle):客户端不应该依赖于它不需要的接口。
  6. 依赖倒置原则Dependence Inversion Principle):高层模块不应该依赖于低层模块,它们都应该依赖于抽象。

一、创建型模式

 用于描述怎样创建对象,它的主要特点是将对象的创建与使用分离。降低系统耦合度,使用者不需要关注对象的创建细节。

1.1 单例模式

 单例模式确保一个类只有一个实例对象,并提供一个全局访问点来访问该实例。Runtime类就是饿汉式的静态变量实现的单例模式

  1. 饿汉式:类加载就会导致该单例对象被创建
     静态变量和静态代码块创建饿汉式单例对象,随着类的加载而加载,如果不使用会造成内存的浪费。
    (1)静态变量
    public class Singleton {
    
        private Singleton() { } // 私有构造函数,防止外部实例化
        
        private static Singleton instance = new Singleton(); // 在成员位置创建该类的对象
        
        public static Singleton getInstance() { // 对外提供静态方法获取该对象
            return instance;
        }
    }
    
    (2)静态代码块
    public class Singleton {
        private Singleton() { } // 私有构造函数,防止外部实例化
    
        private static Singleton instance; // 声明Singleton类型成员变量
    
        static {
            instance = new Singleton(); // 静态代码块创建对象
        }
    
        public static Singleton getInstance() { // 对外提供静态方法获取该对象
            return instance;
        }
    }
    
    (3)枚举类
     枚举类实现单例模式是极力推荐的单例实现模式,因为枚举类型是线程安全的,并且只会装载一次,设计者充分的利用了枚举的这个特性来实现单例模式,枚举的写法非常简单,而且枚举类是所有单例实现中唯一一种不会被破坏的单例实现模式
    public enum Singleton { // 枚举类
        INSTANCE;
    }
    
  2. 懒汉式:类加载不会导致该单例对象被创建,而是首次使用该对象时才会创建
    (1)线程不安全(当多线程调用Singleton.getInstance()时,可能会创建多个实例对象,不符合单例设计模式,可以用synchronized修饰该方法,但这种方法效率特别低)
    public class Singleton {
        private Singleton() { } // 私有构造函数,防止外部实例化
    
        private static Singleton instance; // 声明Singleton类型成员变量
    
        public static Singleton getInstance() { // 对外提供静态方法获取该对象
            if (instance == null) { // 若对象为空,则创建新对象
                instance = new Singleton();
            }
            return instance;
        }
    }
    
    (2)双重检查锁
    public class Singleton {
        private Singleton() { } // 私有构造函数,防止外部实例化
    
        private static volatile Singleton instance; // volatile保证有序性(禁止指令重排导致的空指针异常)
    
        public static Singleton getInstance() { // 对外提供静态方法获取该对象
            if (instance == null) { // 若对象为空,才抢占锁
                synchronized (Singleton.class) {
                    if (instance == null) { // 抢到锁后,只有实例非空才创建
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
    
    (3)静态内部类
     JVM加载外部类的过程中,并不会加载静态内部类,只有当内部类的属性/方法被调用时才会被加载,并初始化其静态属性。静态属性由于被static修饰,保证只被实例化一次,并且严格保证实例化顺序。在没有任何锁的情况下,保证了多线程下的安全,并且没有任何性能影响和空间的浪费。
    public class Singleton {
        private Singleton() { } // 私有构造函数,防止外部实例化
    
        private static class SingletonHolder { // 创建私有静态内部类
            private static final Singleton INSTANCE = new Singleton(); // final修饰防止更改
        }
    
        public static Singleton getInstance() { // 对外提供静态方法获取该对象
            return SingletonHolder.INSTANCE;
        }
    }
    
  3. 破坏单例模式
    序列化、反序列化:对序列化文件反序列化得到的对象是不同的(反序列化是通过类的构造函数创建新的对象,绕过了单例模式的控制),即创建了多个对象,破坏了单例模式。
    反射:通过Class对象的无参构造对象的newInstance()和暂时取消权限验证setAccessible()创建对象也是不同的。
    (1)序列化与反序列化
     反序列化时会查看是否有readResolve方法,若有该方法则执行(通过反射来实现该方法的调用的)。
    public Object readResolve() { // 反序列化时会自动调用该方法,将该方法的返回值直接返回
        return SingletonHolder.INSTANCE; // 这个对应的是静态内部类的,确保返回同一个实例即可
    }
    
    (2)反射
     通过在私有构造函数中判断是否是第一次创建对象来防止反射通过构造器破坏,不是第一次就抛异常。
    private Singleton() { // 私有构造函数,防止外部实例化
        if (instance != null) { 
            throw new RuntimeException("单例模式不能创建多个对象!");
        }
    }
    

1.2 工厂模式

 工厂模式提供了一种将对象的实例化过程封装在工厂类中的方法。通过工厂模式,可以通过调用工厂类的方法来获取所需的对象,而无需直接在客户端代码中使用 new 关键字实例化对象。工厂模式的主要目的是将对象的创建与使用分离(解耦),提供更灵活和可扩展的对象创建方式。

  1. 简单工厂模式(静态工厂模式)
     简单工厂模式将对象的创建逻辑封装在工厂类中,客户端只需要调用工厂的静态方法来获取所需的产品实例,把对象的创建和业务逻辑分开(解耦),避免了客户端的修改。缺点:增加新产品时仍要修改工厂类的代码,违背了开闭原则
     抽象产品 :定义了产品的规范,描述了产品的主要特性和功能。
     具体产品 :实现或者继承抽象产品的子类
     具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。
  2. 工厂方法模式
     定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则(不修改原来代码,新功能可扩展);每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。迭代器就是一种工厂方法模式实现
    抽象工厂:提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
     具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
     抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
     具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
    // 抽象产品
    interface Product {
        void doSomething();
    }
    
    // 具体产品A
    class ConcreteProductA implements Product {
        @Override
        public void doSomething() {
            System.out.println("ConcreteProductA do something");
        }
    }
    
    // 具体产品B
    class ConcreteProductB implements Product {
        @Override
        public void doSomething() {
            System.out.println("ConcreteProductB do something");
        }
    }
    
    // 抽象工厂
    interface Factory {
        Product createProduct();
    }
    
    // 具体工厂A
    class ConcreteFactoryA implements Factory {
        @Override
        public Product createProduct() {
            return new ConcreteProductA();
        }
    }
    
    // 具体工厂B
    class ConcreteFactoryB implements Factory {
        @Override
        public Product createProduct() {
            return new ConcreteProductB();
    }
    
  3. 抽象工厂模式
     抽象工厂模式提供了一种方式来创建一系列相关或依赖对象的家族,而无需指定其具体的类。抽象工厂模式的核心思想是提供一个抽象的工厂接口(或抽象类),该接口定义了创建不同类型对象的方法。具体的工厂类实现这个接口,负责创建一组相关的产品,每个具体工厂类对应一个具体的产品家族。
    抽象工厂:定义了创建产品的接口,可以是接口或抽象类,提供了创建不同类型产品的方法
     具体工厂:实现了抽象工厂定义的创建产品的方法,负责实际创建一组相关的具体产品。
     抽象产品:定义了产品的接口或抽象类,是具体产品类的共同父类或接口。
     具体产品:实现了抽象产品定义的接口,具体产品是工厂所创建的对象。
    // 抽象产品A
    interface ProductA {
        void doSomething();
    }
    
    // 具体产品A1
    class ConcreteProductA1 implements ProductA {
        @Override
        public void doSomething() {
            System.out.println("ConcreteProductA1 do something");
        }
    }
    
    // 具体产品A2
    class ConcreteProductA2 implements ProductA {
        @Override
        public void doSomething() {
            System.out.println("ConcreteProductA2 do something");
        }
    }
    
    // 抽象产品B
    interface ProductB {
        void doSomething();
    }
    
    // 具体产品B1
    class ConcreteProductB1 implements ProductB {
        @Override
        public void doSomething() {
            System.out.println("ConcreteProductB1 do something");
        }
    }
    
    // 具体产品B2
    class ConcreteProductB2 implements ProductB {
        @Override
        public void doSomething() {
            System.out.println("ConcreteProductB2 do something");
        }
    }
    
    // 抽象工厂
    interface AbstractFactory {
        ProductA createProductA();
        ProductB createProductB();
    }
    
    // 具体工厂1
    class ConcreteFactory1 implements AbstractFactory {
        @Override
        public ProductA createProductA() {
            return new ConcreteProductA1();
        }
    
        @Override
        public ProductB createProductB() {
            return new ConcreteProductB1();
        }
    }
    
    // 具体工厂2
    class ConcreteFactory2 implements AbstractFactory {
        @Override
        public ProductA createProductA() {
            return new ConcreteProductA2();
        }
    
        @Override
        public ProductB createProductB() {
            return new ConcreteProductB2();
        }
    }
    

1.3 原型模式

 原型模式用于创建对象的克隆副本,而无需依赖具体类的构造函数。原型模式基于一个现有对象作为原型,并通过克隆来创建新的对象。它在需要创建相似对象且创建过程复杂的场景中具有很好的适用性。
原型(Prototype):原型是一个已存在的对象,它是要被克隆的对象。原型类需要实现 Cloneable 接口,该接口作为标记接口,用于表示该类可以进行克隆。原型类需要重写 clone() 方法,该方法用于复制原型对象并返回新的克隆对象。
克隆(Clone):克隆是通过复制原型对象来创建新的对象。克隆过程可以是浅拷贝(引用类型的成员变量仍和原型指向同一个对象,String类型具有不可变性,因此若改变它的值并不会影响原型对应的值)或深拷贝(完全拷贝,引用类型也是新的对象,对引用数据类型可以同样重写clone或序列化与反序列化实现),取决于对象的复制方式。

1.4 建造者模式

 建造者模(Builder Pattern)提供了一种创建复杂对象的方式,通过逐步构建对象来完成。建造者模式将对象的构建过程与其表示分离,使得相同的构建过程可以创建不同的表示。建造者模式适用于构建复杂对象的场景,特别是当对象具有多个可选参数、参数组合较多或者构建过程需要一定的顺序和逻辑时。它提供了一种更优雅、可扩展的构建对象的方式,使得代码更加灵活和易于维护。
 产品(Product):表示最终构建完成的对象,它包含了被构建的对象所具有的属性和功能。
 抽象建造者(Builder):定义了构建产品的抽象接口,它负责具体步骤的实现。Builder接口通常包含一系列方法,用于构建产品的不同部分。
 具体建造者(ConcreteBuilder):实现了Builder接口,负责实际构建产品的各个部分,并提供一个返回最终产品的方法。
 指导者(Director):负责控制构建过程的执行顺序,并通知建造者进行下一步的构建。它不直接创建最终的产品,而是通过建造者来构建产品。
 假设我们要构建一个汽车对象,并且汽车对象具有多个可选参数,如车型、颜色、引擎类型等。可以使用建造者模式来创建汽车对象。
(1)定义汽车对象(Product)

public class Car {
    private String model;
    private String color;
    private String engineType;

    // 省略构造函数和其他方法

    // 设置汽车车型
    public void setModel(String model) {
        this.model = model;
    }

    // 设置汽车颜色
    public void setColor(String color) {
        this.color = color;
    }

    // 设置汽车引擎类型
    public void setEngineType(String engineType) {
        this.engineType = engineType;
    }

    // 省略其他属性的设置方法
}

(2)定义汽车建造者(Builder)接口和具体建造者(Concrete Builder)

public abstract class CarBuilder { // 抽象汽车建造者类
    protected Car car;

    public Car getCar() {
        return car;
    }

    public void createNewCar() {
        car = new Car();
    }

    public abstract void setModel();
    public abstract void setColor();
    public abstract void setEngineType();
}

public class SportsCarBuilder extends CarBuilder { // 跑车建造者
    @Override
    public void setModel() {
        car.setModel("Sports Car");
    }

    @Override
    public void setColor() {
        car.setColor("Red");
    }

    @Override
    public void setEngineType() {
        car.setEngineType("V8");
    }
}

public class SUVBuilder extends CarBuilder { // SUV建造者
    @Override
    public void setModel() {
        car.setModel("SUV");
    }

    @Override
    public void setColor() {
        car.setColor("Black");
    }

    @Override
    public void setEngineType() {
        car.setEngineType("V6");
    }
}

(3)使用指导者(Director)来控制构建过程

public class CarDirector {
	private CarBuilder builder;

	public CarDirector(CarBuilder builder) { // 有参构造将构造者注入
		this.builder = builder;
	}

    public Car constructCar() { 
        builder.createNewCar();
        builder.setModel();
        builder.setColor();
        builder.setEngineType();
        return builder.getCar();
    }
}

(4)使用建造者模式

CarDirector director = new CarDirector(new SportsCarBuilder());
Car sportsCar = director.constructCar();
System.out.println(sportsCar.getModel()); // 输出: Sports Car
System.out.println(sportsCar.getColor()); // 输出: Red
System.out.println(sportsCar.getEngineType()); // 输出: V8

CarDirector director1 = new CarDirector(new SUVBuilder());
Car suv = director1.constructCar();
System.out.println(suv.getModel()); // 输出: SUV
System.out.println(suv.getColor()); // 输出: Black
System.out.println(suv.getEngineType()); // 输出: V6

 当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用建造者模式进行重构。

public class Phone {
    private String cpu;
    private String screen;
    private String memory;
    private String mainboard;

    private Phone(Builder builder) {
        cpu = builder.cpu;
        screen = builder.screen;
        memory = builder.memory;
        mainboard = builder.mainboard;
    }

    public static final class Builder {
        private String cpu;
        private String screen;
        private String memory;
        private String mainboard;

        public Builder() {
        }

        public Builder cpu(String val) {
            cpu = val;
            return this;
        }

        public Builder screen(String val) {
            screen = val;
            return this;
        }

        public Builder memory(String val) {
            memory = val;
            return this;
        }

        public Builder mainboard(String val) {
            mainboard = val;
            return this;
        }

        public Phone build() {
            return new Phone(this);
        }
    }

    @Override
    public String toString() {
        return "Phone{" +
                "cpu='" + cpu + '\'' +
                ", screen='" + screen + '\'' +
                ", memory='" + memory + '\'' +
                ", mainboard='" + mainboard + '\'' +
                '}';
    }
}

public class Client {
    public static void main(String[] args) {
        Phone phone = new Phone.Builder()
                .cpu("intel")
                .mainboard("华硕")
                .memory("金士顿")
                .screen("三星")
                .build();
        System.out.println(phone);
    }
}

1.5 创建者模式对比

  1. 工厂方法模式 VS. 建造者模式
     工厂方法模式注重的是整体对象的创建方式;而建造者模式注重的是部件构建的过程,意在通过一步一步地精确构造创建出一个复杂的对象。比如要制造一个超人,如果使用工厂方法模式,直接产生出来的就是一个力大无穷、能够飞翔、内裤外穿的超人;而如果使用建造者模式,则需要组装手、头、脚、躯干等部分,然后再把内裤外穿,于是一个超人就诞生了。
  2. 抽象工厂模式 VS. 建造者模式
     抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式则是不需要关心构建过程,只关心什么产品由什么工厂生产即可。建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车。

二、结构型模式

 用于描述如何将类或对象按某种布局组成更大的结构,以解决对象之间的组合和接口定义的问题。结构型模式主要涉及对象之间的组合、关联和装饰等关系,以实现更灵活、可复用和可扩展的系统架构。它分为类结构型模式对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。

2.1 代理模式

 使用代理对象来代替对真实对象的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。分为静态代理(编译时就生成类字节码)和动态代理(运行时动态生成类字节码)。静态代理中,接口一旦新增加方法,目标对象和代理对象都要进行修改

  1. 静态代理
    (1)定义一个接口及其实现类;
    (2)创建一个代理类同样实现这个接口;
    (3)将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情。

  2. JDK动态代理
    (1)定义一个接口及其实现类;
    (2)自定义InvocationHandler并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;可以以匿名内部类的形式创建。
    (3)通过 Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 方法创建代理对象,需要强转为接口类型的代理对象(代理对象也实现了接口,本质是多态+反射实现的动态代理);

  3. CGLIB动态代理
    (1)定义一个类;
    (2)自定义MethodInterceptor并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似;
    (3)通过Enhancer类(类似JDK 动态代理中的Proxy类)的 create()创建代理类;

    public class AliSmsService { // 创建目标类
        public String send(String message) {
            System.out.println("send message:" + message);
            return message;
        }
    }
    
    public class DebugMethodInterceptor implements MethodInterceptor { //自定义MethodInterceptor实现类
        /**
         * @param o           被代理的对象(需要增强的对象)
         * @param method      被拦截的方法(需要增强的方法)
         * @param args        方法入参
         * @param methodProxy 用于调用原始方法
         */
        @Override
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            //调用方法之前,我们可以添加自己的操作
            System.out.println("before method " + method.getName());
            Object object = methodProxy.invokeSuper(o, args);
            //调用方法之后,我们同样可以添加自己的操作
            System.out.println("after method " + method.getName());
            return object;
        }
    }
    
    public class CglibProxyFactory { // 创建代理类工厂
        public static Object getProxy(Class<?> clazz) {
            // 创建动态代理增强类
            Enhancer enhancer = new Enhancer();
            // 设置类加载器
            enhancer.setClassLoader(clazz.getClassLoader());
            // 设置被代理类(即代理类的父类)
            enhancer.setSuperclass(clazz);
            // 设置方法拦截器
            enhancer.setCallback(new DebugMethodInterceptor());
            // 创建代理类
            return enhancer.create();
        }
    }
    
    AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class); // 代理类的使用
    aliSmsService.send("java");
    
  4. JDK动态代理 VS. CGLib动态代理
     JDK动态代理只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代理未实现任何接口的类。 另外, CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为 final 类型的类和方法。在Spring中,如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理。

2.2 适配器模式

 适配器模式用于将一个类的接口转换为另一个类的接口,使得原本由于接口不兼容而无法工作的类能够一起工作。适配器模式分为类适配器模式(继承)和对象适配器模式(组合),前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。
 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口,即需要被适配的类,它的接口与目标接口不兼容。
 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

  1. 类适配器模式:适配器类继承适配者类并实现目标接口。类适配器模式违背了合成复用原则。类适配器是客户类有一个接口规范的情况下可用,反之不可用。

    // 目标接口
    public interface Target {
        void request();
    }
    
    // 适配者类(源类)
    public class Adaptee {
        public void specificRequest() {
            System.out.println("Adaptee's specificRequest() method called.");
        }
    }
    
    // 适配器类(类适配器)
    public class Adapter extends Adaptee implements Target {
        @Override
        public void request() {
            specificRequest();  // 调用适配者类的方法
        }
    }
    
    // 客户端代码
    public class Client {
        public static void main(String[] args) {
            Target target = new Adapter();
            target.request();
        }
    }
    
  2. 对象适配器模式:适配器类实现目标接口,并创建适配者类成员变量(聚合/组合)。即使目标接口不是接口,而是类,也可以继承实现。

    // 目标接口
    public interface Target {
        void request();
    }
    
    // 适配者类(源类)
    public class Adaptee {
        public void specificRequest() {
            System.out.println("Adaptee's specificRequest() method called.");
        }
    }
    
    // 适配器类(对象适配器)
    public class Adapter implements Target { // 即使目标接口不是接口,也可以用继承实现
        private Adaptee adaptee;
    
        public Adapter(Adaptee adaptee) {
            this.adaptee = adaptee;
        }
    
        @Override
        public void request() {
            adaptee.specificRequest();  // 调用适配者类的方法
        }
    }
    
    // 客户端代码
    public class Client {
        public static void main(String[] args) {
            Adaptee adaptee = new Adaptee();
            Target target = new Adapter(adaptee);
            target.request();
        }
    }
    
  3. 接口适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Adapter ,实现所有方法。而此时我们只需要继承该抽象类即可。

  4. InputStreamReader:封装了StreamDecoder,StreamDecoder(适配器类)聚合了InputStream(适配者类)并继承了抽象类Reader(目标接口),进而实现了将字节输入流转换为字符输出流。JDK中一个标准的对象适配器模式。

2.3 装饰者模式

 装饰者模式允许在不改变原有对象结构的情况下,动态地将新功能附加到对象上。继承是静态的附加责任,装饰者则是动态的附加责任。装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。继承或实现并聚合,如IO流中的包装类,BufferedInputStream、BufferedWriter(继承并聚合了Writer)等。
 抽象组件(Component)角色 :定义一个抽象接口以规范准备接收附加责任的对象。
 具体组件(Concrete Component)角色 :实现抽象组件,通过装饰角色为其添加一些职责。
 抽象装饰(Decorator)角色 : 继承或实现抽象组件,并包含具体组件的实例,可以通过其子类扩展具体构件的功能。
 具体装饰(ConcreteDecorator)角色 :实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
静态代理 VS. 装饰者模式
相同点:
 都要实现与目标类相同的业务接口
 在两个类中都要声明目标对象
 都可以在不修改目标类的前提下增强目标方法
不同点:
 目的不同:装饰者是为了增强目标对象;静态代理是为了保护和隐藏目标对象
 获取目标对象构建的地方不同:装饰者是由外界传递进来,可以通过构造方法传递;静态代理是在代理类内部创建,以此来隐藏目标对象。

// 抽象组件(饮料)
public interface Beverage { 
    double cost();
}

// 具体组件(浓咖啡)
public class Espresso implements Beverage {
    @Override
    public double cost() {
        return 1.99;
    }
}

// 具体组件(混合咖啡)
public class HouseBlend implements Beverage { 
    @Override
    public double cost() {
        return 0.99;
    }
}

// 抽象装饰者(调料)
public abstract class CondimentDecorator implements Beverage { // 实现或继承抽象组件
    protected Beverage beverage; // 聚合抽象组件
}

// 具体装饰者(摩卡,一种调料)
public class Mocha extends CondimentDecorator {
    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public double cost() {
        return beverage.cost() + 0.20;
    }
}

// 具体装饰者(奶泡,一种调料)
public class Whip extends CondimentDecorator {
    public Whip(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public double cost() {
        return beverage.cost() + 0.10;
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Beverage beverage = new Espresso(); // 浓咖啡饮料,也可换成HouseBlend混合咖啡饮料
        beverage = new Mocha(beverage); // 加摩卡
        beverage = new Whip(beverage); // 加奶泡
        System.out.println("Cost: " + beverage.cost());
    }
}

2.4 桥接模式

 桥接模式用于将抽象部分与实现部分分离,使它们能够独立地变化。桥接模式的关键思想是通过组合关系而不是继承关系来连接不同的抽象和实现。桥接模式的核心是将抽象部分与实现部分分离,使得它们可以独立地变化和扩展。抽象部分通过对实现部分的引用,将具体的实现委托给实现部分,从而实现抽象和实现的解耦,使它们可以独立地变化和扩展,提高了系统的灵活性和可扩展性。当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时可使用桥接模式。
 抽象化(Abstraction)角色 :定义抽象类,并包含一个对实现化对象的引用。
 扩展抽象化(Refined Abstraction)角色 :是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
 实现化(Implementor)角色 :定义实现化角色的接口,供扩展抽象化角色调用。
 具体实现化(Concrete Implementor)角色 :给出实现化角色接口的具体实现。

// 实现化角色
public interface Color {
    void applyColor();
}

// 具体实现化角色(红色)
public class Red implements Color { 
    @Override
    public void applyColor() {
        System.out.println("Applying red color");
    }
}

// 具体实现化角色(蓝色)
public class Blue implements Color {
    @Override
    public void applyColor() {
        System.out.println("Applying blue color");
    }
}

// 抽象化角色(形状,聚合了实现化角色-颜色)
public abstract class Shape {
    protected Color color;

    public Shape(Color color) {
        this.color = color;
    }

    public abstract void applyColor();
}

// 具体抽象化角色(正方体)
public class Square extends Shape {
    public Square(Color color) {
        super(color);
    }

    @Override
    public void applyColor() {
        System.out.print("Square filled with ");
        color.applyColor();
    }
}

// 具体抽象化角色(园)
public class Circle extends Shape {
    public Circle(Color color) {
        super(color);
    }

    @Override
    public void applyColor() {
        System.out.print("Circle filled with ");
        color.applyColor();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Shape redSquare = new Square(new Red()); // 红色正方体
        redSquare.applyColor();

        Shape blueCircle = new Circle(new Blue()); // 蓝色圆
        blueCircle.applyColor();
    }
}

2.5 外观模式

 外观模式提供了一个简化的接口,用于访问复杂子系统的一组接口。外观模式通过创建一个高层接口,隐藏了子系统的复杂性,并为客户端提供了一个简单的接口。外观类充当了客户端和子系统之间的中间层,简化了客户端的使用方式。降低了子系统与客户端之间的耦合度,使得子系统的变化不会影响调用它的客户类。对客户屏蔽了子系统组件,减少了客户处理的对象数目,并使得子系统使用起来更加容易。单不符合开闭原则,修改很麻烦。
 外观(Facade)角色:为多个子系统对外提供一个共同的接口。
 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。

// 子系统类
public class SubsystemA {
    public void operationA() {
        System.out.println("SubsystemA operation");
    }
}

public class SubsystemB {
    public void operationB() {
        System.out.println("SubsystemB operation");
    }
}

public class SubsystemC {
    public void operationC() {
        System.out.println("SubsystemC operation");
    }
}

// 外观类
public class Facade {
    private SubsystemA subsystemA;
    private SubsystemB subsystemB;
    private SubsystemC subsystemC;

    public Facade() {
        subsystemA = new SubsystemA();
        subsystemB = new SubsystemB();
        subsystemC = new SubsystemC();
    }

    public void doOperation() {
        subsystemA.operationA();
        subsystemB.operationB();
        subsystemC.operationC();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.doOperation();
    }
}

2.6 组合模式

 组合模式允许将对象组合成树状结构,并且能够以统一的方式处理单个对象和组合对象。使用场景就是出现树形结构的地方。比如:文件目录显示,多级目录呈现、多级菜单等树形结构数据的操作。
 抽象根节点(Component):定义系统各层次对象的共有方法和属性,可以预先定义一些默认行为和属性。
 树枝节点(Composite):定义树枝节点的行为,存储子节点,组合树枝节点和叶子节点形成一个树形结构。
 叶子节点(Leaf):叶子节点对象,其下再无分支,是系统层次遍历的最小单位。
透明组合模式:抽象根节点角色中声明了所有用于管理成员对象的方法,好处是确保所有的构件类都有相同的接口,透明组合模式也是组合模式的标准形式。缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的,叶子对象不可能有下一个层次的对象,在运行阶段如果调用这些方法可能会出错。
安全组合模式:在抽象构件角色中没有声明任何用于管理成员对象的方法,而是在树枝节点类中声明并实现这些方法。缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。

// 抽象根结点
abstract class MenuComponent { // 透明组合模式,在根节点声明了全部管理成员对象的方法
    protected String name;

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

    public abstract void display();

    public void addComponent(MenuComponent component) {
        throw new UnsupportedOperationException("不支持添加操作");
    }

    public void removeComponent(MenuComponent component) {
        throw new UnsupportedOperationException("不支持移除操作");
    }

    public MenuComponent getChild(int index) {
        throw new UnsupportedOperationException("不支持获取子组件操作");
    }
}

// 叶子节点类,表示菜单项
class MenuItem extends MenuComponent {
    public MenuItem(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("菜单项: " + name);
    }
}

// 树枝节点类,表示菜单
class Menu extends MenuComponent {
    private List<MenuComponent> components;

    public Menu(String name) {
        super(name);
        components = new ArrayList<>();
    }

    @Override
    public void display() {
        System.out.println("菜单: " + name);
        for (MenuComponent component : components) {
            component.display();
        }
    }

    @Override
    public void addComponent(MenuComponent component) {
        components.add(component);
    }

    @Override
    public void removeComponent(MenuComponent component) {
        components.remove(component);
    }

    @Override
    public MenuComponent getChild(int index) {
        return components.get(index);
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建菜单项
        MenuItem menuItem1 = new MenuItem("菜单项1");
        MenuItem menuItem2 = new MenuItem("菜单项2");
        MenuItem menuItem3 = new MenuItem("菜单项3");

        // 创建子菜单
        Menu submenu = new Menu("子菜单");
        MenuItem submenuItem1 = new MenuItem("子菜单项1");
        MenuItem submenuItem2 = new MenuItem("子菜单项2");
        submenu.addComponent(submenuItem1);
        submenu.addComponent(submenuItem2);

        // 创建主菜单(三个菜单项和一个子菜单)
        Menu menu = new Menu("主菜单");
        menu.addComponent(menuItem1);
        menu.addComponent(menuItem2);
        menu.addComponent(menuItem3);
        menu.addComponent(submenu);

        // 显示整个菜单导航系统
        menu.display();
    }
}

2.7 享元模式

 享元模式旨在有效地支持大量细粒度对象的共享使用,以减少内存占用和提高性能。极大减少内存中相似或相同对象数量,节约系统资源,提升系统性能;享元模式中的外部状态相对独立,且不影响内部状态。Integer等包装类的缓存机制就用到了享元模式。Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character 创建了数值在 [0,127] 范围的缓存数据,Boolean 直接返回 True or False。
内部状态:即不会随着环境的改变而改变的可共享部分。
外部状态:指随环境改变而改变的不可以共享的部分。
 享元模式的实现要领就是区分应用中的这两种状态,并将外部状态外部化(以参数传入)。
 享元接口(Flyweight):定义了享元对象的接口,包含了操作内部状态和接受外部状态的方法。
 具体享元(Concrete Flyweight):实现了享元接口,表示可以共享的具体享元对象。
 非享元(Unsharable Flyweight)角色:实现了享元接口,表示可以非共享的具体享元对象。
 享元工厂(Flyweight Factory):负责创建和管理享元对象,提供了享元对象的获取和共享的方法。

// 享元接口(俄罗斯方块)
public abstract class AbstractBox {
    public abstract String getShape(); // 形状(内部状态)

    public void display(String color) { // 颜色(外部状态,通过外部传参获取)
        System.out.println("方块形状:" + this.getShape() + " 颜色:" + color);
    }
}

// 具体享元(I型方块)
public class IBox extends AbstractBox {
    @Override
    public String getShape() {
        return "I";
    }
}

// 具体享元(L型方块)
public class LBox extends AbstractBox {
    @Override
    public String getShape() {
        return "L";
    }
}

// 具体享元(O型方块)
public class OBox extends AbstractBox {
    @Override
    public String getShape() {
        return "O";
    }
}

// 单例工厂来管理享元对象
public class BoxFactory {
    private static HashMap<String, AbstractBox> map;

    private BoxFactory() {
        map = new HashMap<String, AbstractBox>();
        AbstractBox iBox = new IBox();
        AbstractBox lBox = new LBox();
        AbstractBox oBox = new OBox();
        map.put("I", iBox);
        map.put("L", lBox);
        map.put("O", oBox);
    }

    public static BoxFactory getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder { // 静态内部类实现单例(懒汉式)
        private static final BoxFactory INSTANCE = new BoxFactory();
    }

    public AbstractBox getBox(String name) { // 根据名称获取图形对象
        return map.get(name);
    }
}

public class Main {
    public static void main(String[] args) {
        AbstractBox box1 = BoxFactory.getInstance().getBox("I");
        box1.display("灰色");

        AbstractBox box2 = BoxFactory.getInstance().getBox("L");
        box2.display("红色");

        AbstractBox box3 = BoxFactory.getInstance().getBox("O");
        box3.display("蓝色");

        AbstractBox box4 = BoxFactory.getInstance().getBox("O");
        box4.display("黑色");

        System.out.println("两次获取到的O图形对象是否是同一个对象:" + (box3 == box4));
    }
}

三、行为型模式

 用于描述类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,以及怎样分配职责。行为型模式分为类行为模式(继承)和对象行为模式(组合或聚合,耦合度较低,满足合成复用,更加灵活)。

3.1 模板方法模式

 模板方法模式定义了一个操作中的算法框架,将一些步骤的具体实现延迟到子类中。模板方法模式使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。InputStream中定义了多个read方法,其中无参read就是供子类实现,有参read方法调用了无参read方法
 抽象类(Abstract Class):定义了模板方法和抽象方法,作为算法的骨架。抽象方法由子类实现,模板方法使用这些方法来定义算法的结构。
 具体类(Concrete Class):继承抽象类,实现抽象方法,提供算法中具体步骤的实现。

// 抽象类,定义咖啡制作的算法骨架
abstract class CoffeeMaker {
    // 模板方法,定义咖啡制作的流程
    public final void makeCoffee() { // 定义为final,防止子类更改模板
        boilWater();
        brewCoffee();
        pourInCup();
        addSugarAndMilk();
        System.out.println("咖啡制作完成");
    }

    // 具体步骤,煮水
    public void boilWater() {
        System.out.println("煮水");
    }

    // 抽象方法,冲泡咖啡
    public abstract void brewCoffee();

    // 具体步骤,倒入杯子
    public void pourInCup() {
        System.out.println("倒入杯子");
    }

    // 具体步骤,加糖和牛奶
    public void addSugarAndMilk() {
        System.out.println("加糖和牛奶");
    }
}

// 具体类,实现冲泡咖啡的具体步骤
class Coffee extends CoffeeMaker {
    @Override
    public void brewCoffee() {
        System.out.println("冲泡咖啡");
    }
}

public class Main {
    public static void main(String[] args) {
        Coffee coffee = new Coffee();
        coffee.makeCoffee();
    }
}

3.2 策略模式

 策略模式允许在运行时选择算法的行为。它将算法封装在可互换的策略对象中,使得可以根据需求动态地选择使用不同的算法。Arrays.sort(数组, Comparator),其中Comparator相当于抽象策略,其具体实现类相当于具体策略类。
 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
 环境(Context)类:持有一个策略类的引用,最终给客户端调用。

// 抽象策略(促销)
public interface DiscountStrategy {
    double calculateDiscount(double price);
}

// 具体策略(固定金额)
public class FixedDiscountStrategy implements DiscountStrategy {
    private double discountAmount;

    public FixedDiscountStrategy(double discountAmount) {
        this.discountAmount = discountAmount;
    }

    @Override
    public double calculateDiscount(double price) {
        return price - discountAmount;
    }
}

// 具体策略(金额百分比)
public class PercentageDiscountStrategy implements DiscountStrategy {
    private double discountPercentage;

    public PercentageDiscountStrategy(double discountPercentage) {
        this.discountPercentage = discountPercentage;
    }

    @Override
    public double calculateDiscount(double price) {
        return price - (price * discountPercentage / 100);
    }
}

// 环境类,包含促销策略的引用
public class Product {
    private double price;
    private DiscountStrategy discountStrategy;

    public Product(double price, DiscountStrategy discountStrategy) {
        this.price = price;
        this.discountStrategy = discountStrategy;
    }

	public void setDiscountStrategy(DiscountStrategy discountStrategy) { // set方法用于切换策略
		this.discountStrategy = discountStrategy;
	}

    public double calculateDiscountedPrice() {
        return discountStrategy.calculateDiscount(price);
    }
}

public class Main {
    public static void main(String[] args) {
        Product product1 = new Product(100, new FixedDiscountStrategy(20)); // 固定金额
        System.out.println("Discounted Price: " + product1.calculateDiscountedPrice());

        Product product2 = new Product(200, new PercentageDiscountStrategy(10)); // 百分比
        System.out.println("Discounted Price: " + product2.calculateDiscountedPrice());
    }
}

3.3 命令模式

 命令模式将请求封装为一个对象,从而允许你使用不同的请求、队列或日志来参数化客户端对象。命令模式可以将请求的发送者和接收者解耦,使得发送者无需知道具体的接收者,只需通过命令对象来执行相应的操作。Runable是一个典型命令模式,Runnable担当命令的角色,具体命令用户自己实现,Thread充当的是调用者,start方法就是其执行方法。
 命令(Command):命令是一个接口或抽象类,它定义了执行操作的方法。具体的命令类实现了命令接口,并实现了具体的操作。
 具体命令(Concrete Command):具体命令是命令接口的实现类,它封装了具体的操作和接收者。它通常会持有一个接收者对象,并在调用时执行相应的操作。
 接收者(Receiver):接收者是实际执行操作的对象。它包含了具体的业务逻辑,并定义了实际的操作方法。
 调用者(Invoker):调用者是请求的发送者,它持有一个命令对象,并在需要执行操作时调用命令对象的执行方法。

// 抽象命令
public interface Command {
    void execute();
}

// 具体命令(打开设备)
public class TurnOnCommand implements Command {
    private ElectronicDevice device;

    public TurnOnCommand(ElectronicDevice device) { // 聚合/组合了接收者
        this.device = device;
    }

    @Override
    public void execute() {
        device.turnOn();
    }
}

// 具体命令(关闭设备)
public class TurnOffCommand implements Command {
    private ElectronicDevice device;

    public TurnOffCommand(ElectronicDevice device) {
        this.device = device;
    }

    @Override
    public void execute() {
        device.turnOff();
    }
}

public interface ElectronicDevice { // 这个(抽象策略)和它的实现类(具体策略)以及具体命令(环境)又构成了一个策略模式
    void turnOn();
    void turnOff();
}

// 接收者(电视)
public class Television implements ElectronicDevice {
    @Override
    public void turnOn() { // 具体实现
        System.out.println("TV is turned on");
    }

    @Override
    public void turnOff() {
        System.out.println("TV is turned off");
    }
}

// 调用者(遥控器类)
public class RemoteControl {
    private Command command;

    public void setCommand(Command command) { // 聚合了命令
        this.command = command;
    }

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

public class Main {
    public static void main(String[] args) {
        RemoteControl remoteControl = new RemoteControl(); // 调用者(遥控器)

        ElectronicDevice tv = new Television(); // 接收者(电视)
        Command turnOnCommand = new TurnOnCommand(tv); // 打开命令
        Command turnOffCommand = new TurnOffCommand(tv); // 关闭命令

        remoteControl.setCommand(turnOnCommand); // 遥控器执行打开命令
        remoteControl.pressButton();

        remoteControl.setCommand(turnOffCommand); // 遥控器执行关闭命令
        remoteControl.pressButton();
    }
}

3.4 职责链模式

 职责链模式用于将请求的发送者和接收者解耦,并允许多个对象依次处理请求。职责链模式形成一个链式结构,请求沿着链传递,直到有一个对象能够处理它为止。FilterChain 过滤器链就是职责链模式。
 处理者(Handler):处理者是一个接口或抽象类,它定义了处理请求的方法,并可以指定下一个处理者。通常,处理者包含一个指向下一个处理者的引用。
 具体处理者(Concrete Handler):具体处理者是处理请求的实际实现类。它实现了处理者接口,并根据自身的逻辑决定是否处理请求,或将请求传递给下一个处理者
 客户端(Client):客户端是发送请求的对象。它将请求发送给职责链的第一个处理者,并在链上传递请求。

// 处理者(支付处理器接口)
public interface PaymentHandler {
    void handlePayment(float amount);
}

// 具体处理者(支付宝支付,当金额>100时,传递给下一个处理者)
public class AlipayHandler implements PaymentHandler {
    private PaymentHandler nextHandler;

    @Override
    public void handlePayment(float amount) {
        if (amount <= 100) {
            System.out.println("Payment handled by Alipay");
        } else if (nextHandler != null) {
            nextHandler.handlePayment(amount);
        } else {
            System.out.println("No payment handler found for the amount.");
        }
    }

    public void setNextHandler(PaymentHandler nextHandler) {
        this.nextHandler = nextHandler;
    }
}

// 具体处理者(微信支付,当金额>200时,传递给下一个处理者)
public class WeChatPayHandler implements PaymentHandler {
    private PaymentHandler nextHandler;

    @Override
    public void handlePayment(float amount) {
        if (amount <= 200) {
            System.out.println("Payment handled by WeChat Pay");
        } else if (nextHandler != null) {
            nextHandler.handlePayment(amount);
        } else {
            System.out.println("No payment handler found for the amount.");
        }
    }

    public void setNextHandler(PaymentHandler nextHandler) {
        this.nextHandler = nextHandler;
    }
}

// 具体处理者(银行支付,当金额<=200时,传递给下一个处理者)
public class BankCardHandler implements PaymentHandler {
    private PaymentHandler nextHandler;

    @Override
    public void handlePayment(float amount) {
        if (amount > 200) {
            System.out.println("Payment handled by Bank Card");
        } else if (nextHandler != null) {
            nextHandler.handlePayment(amount);
        } else {
            System.out.println("No payment handler found for the amount.");
        }
    }

    public void setNextHandler(PaymentHandler nextHandler) {
        this.nextHandler = nextHandler;
    }
}

// 支付请求类,用于存储支付金额和支付方式
public class PaymentRequest {
    private float amount;
    private String paymentMethod;

    public PaymentRequest(float amount, String paymentMethod) {
        this.amount = amount;
        this.paymentMethod = paymentMethod;
    }

    public float getAmount() {
        return amount;
    }

    public String getPaymentMethod() {
        return paymentMethod;
    }
}

public class Main {
    public static void main(String[] args) {
        PaymentHandler alipayHandler = new AlipayHandler();
        PaymentHandler weChatPayHandler = new WeChatPayHandler();
        PaymentHandler bankCardHandler = new BankCardHandler();

        alipayHandler.setNextHandler(weChatPayHandler); // 责任链传递(支付宝->微信)
        weChatPayHandler.setNextHandler(bankCardHandler); // 责任链传递(微信->银行)

        PaymentRequest request1 = new PaymentRequest(50, "Alipay");
        alipayHandler.handlePayment(request1.getAmount());

        PaymentRequest request2 = new PaymentRequest(150, "WeChat Pay");
        alipayHandler.handlePayment(request2.getAmount());

        PaymentRequest request3 = new PaymentRequest(300, "Bank Card");
        alipayHandler.handlePayment(request3.getAmount());
    }
}

3.5 状态模式

 状态模式用于在对象内部状态改变时改变其行为。状态模式允许对象基于其内部状态的改变而改变其行为,使得对象在不同状态下可以表现出不同的行为。
 上下文(Context):上下文是拥有状态的对象,它包含一个当前状态的引用。上下文通常会将请求委派给当前状态对象来处理。
 状态(State):状态是一个接口或抽象类,它定义了不同状态下的行为。每个具体状态类都实现了状态接口,并根据具体状态的逻辑来处理请求。
 具体状态(Concrete States):具体状态是状态接口的具体实现。每个具体状态类实现了状态接口的方法,并根据自身的逻辑来处理请求。

// 状态(订单状态)
public interface OrderState {
    void confirmPayment(Order order);
    void cancelPayment(Order order);
    void shipOrder(Order order);
    void completeOrder(Order order);
}

// 具体状态(新建订单)
public class NewState implements OrderState {
    @Override
    public void confirmPayment(Order order) {
        System.out.println("Confirming payment in New state");
        order.setState(new PaymentPendingState());
    }

    @Override
    public void cancelPayment(Order order) {
        System.out.println("Cannot cancel payment in New state");
    }

    @Override
    public void shipOrder(Order order) {
        System.out.println("Cannot ship order in New state");
    }

    @Override
    public void completeOrder(Order order) {
        System.out.println("Cannot complete order in New state");
    }
}

// 具体状态(支付待确认)
public class PaymentPendingState implements OrderState {
    @Override
    public void confirmPayment(Order order) {
        System.out.println("Payment confirmed");
        order.setState(new PaidState());
    }

    @Override
    public void cancelPayment(Order order) {
        System.out.println("Payment cancelled");
        order.setState(new NewState());
    }

    @Override
    public void shipOrder(Order order) {
        System.out.println("Cannot ship order in Payment Pending state");
    }

    @Override
    public void completeOrder(Order order) {
        System.out.println("Cannot complete order in Payment Pending state");
    }
}

// 其他具体状态类的实现类似...

// 上下文(订单类)
public class Order {
    private OrderState currentState;

    public Order() {
        this.currentState = new NewState();
    }

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

    public void confirmPayment() {
        currentState.confirmPayment(this);
    }

    public void cancelPayment() {
        currentState.cancelPayment(this);
    }

    public void shipOrder() {
        currentState.shipOrder(this);
    }

    public void completeOrder() {
        currentState.completeOrder(this);
    }
}

public class Main {
    public static void main(String[] args) {
        Order order = new Order();

        order.confirmPayment();  // 输出 "Confirming payment in New state"

        order.cancelPayment();   // 输出 "Payment cancelled"

        order.confirmPayment();  // 输出 "Payment confirmed"

        order.shipOrder();       // 输出 "Cannot ship order in Payment Pending state"
    }
}

3.6 观察者模式

 观察者模式(发布-订阅模式)用于在对象之间定义一种一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖它的对象都能得到通知并自动更新。 java.util.Observable类(主题)和 java.util.Observer接口(观察者)就是观察者模式。
 主题(Subject):主题是被观察的对象,它维护了一组观察者对象的列表,提供了添加、删除和通知观察者的方法。
 观察者(Observer):观察者是依赖于主题的对象,当主题的状态发生变化时,观察者会接收到通知并进行相应的更新。

// 主题接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 观察者接口
interface Observer {
    void update();
}

// 具体主题类
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>(); // 用于维护一组观察者对象

    @Override
    public void registerObserver(Observer observer) { // 注册观察者
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) { // 删除观察者
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() { // 通知所有观察者
        for (Observer observer : observers) {
            observer.update();
        }
    }

    // 具体主题类的其他方法
}

// 具体观察者类
class ConcreteObserver implements Observer {
    private String name;

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

    @Override
    public void update() {
        System.out.println("Observer " + name + " received update");
    }
}

// 客户端
public class Main {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        Observer observer1 = new ConcreteObserver("Observer 1");
        Observer observer2 = new ConcreteObserver("Observer 2");

        subject.registerObserver(observer1);
        subject.registerObserver(observer2);

        // 当主题状态发生变化时,通知观察者
        subject.notifyObservers();
    }
}

3.7 中介者模式

 中介者模式通过提供一个中介者对象来协调一组对象之间的交互。中介者模式通过减少对象之间的直接交互,将复杂的相互关系转移到中介者对象中,从而降低了对象之间的耦合性。
 中介者(Mediator):中介者是一个接口或抽象类,定义了对象之间交互的方法。它通常持有一组对象的引用,并负责协调它们之间的交互。
 具体中介者(Concrete Mediator):具体中介者是中介者接口的具体实现。它通过协调各个对象之间的交互来实现中介者的行为。
 同事(Colleague):同事是指参与中介者模式的对象。每个同事对象都持有一个中介者的引用,用于与其他同事对象进行通信。

// 中介者接口
interface Mediator {
    void sendMessage(String message, Colleague colleague);
}

// 具体中介者类
class ConcreteMediator implements Mediator {
    private Colleague colleague1;
    private Colleague colleague2;

    public void setColleague1(Colleague colleague1) {
        this.colleague1 = colleague1;
    }

    public void setColleague2(Colleague colleague2) {
        this.colleague2 = colleague2;
    }

    @Override
    public void sendMessage(String message, Colleague colleague) {
        if (colleague == colleague1) {
            colleague2.receiveMessage(message);
        } else if (colleague == colleague2) {
            colleague1.receiveMessage(message);
        }
    }
}

// 同事接口
interface Colleague {
    void sendMessage(String message);
    void receiveMessage(String message);
}

// 具体同事类1
class ConcreteColleague1 implements Colleague {
    private Mediator mediator;

    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    public void sendMessage(String message) {
        mediator.sendMessage(message, this);
    }

    @Override
    public void receiveMessage(String message) {
        System.out.println("Colleague 1 received message: " + message);
    }
}

// 具体同事类2
class ConcreteColleague2 implements Colleague {
    private Mediator mediator;

    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    @Override
    public void sendMessage(String message) {
        mediator.sendMessage(message, this);
    }

    @Override
    public void receiveMessage(String message) {
        System.out.println("Colleague 2 received message: " + message);
    }
}

// 客户端
public class Main {
    public static void main(String[] args) {
        ConcreteMediator mediator = new ConcreteMediator();

        ConcreteColleague1 colleague1 = new ConcreteColleague1();
        ConcreteColleague2 colleague2 = new ConcreteColleague2();

        mediator.setColleague1(colleague1);
        mediator.setColleague2(colleague2);

        colleague1.sendMessage("Hello from Colleague 1");
        colleague2.sendMessage("Hi from Colleague 2");
    }
}

3.8 迭代器模式

 迭代器模式提供了一种顺序访问聚合对象中各个元素的方法,而不需要暴露聚合对象的内部表示。迭代器模式将遍历和聚合分离,使得客户端能够以统一的方式访问聚合对象中的元素,而不需要了解其内部结构。单列集合的iterator方法就是迭代器模式。
 迭代器(Iterator):迭代器是一个接口或抽象类,定义了访问和遍历元素的方法。它通常包含有获取下一个元素、判断是否还有元素等方法。
 具体迭代器(Concrete Iterator):具体迭代器是迭代器接口的具体实现,它实现了迭代器定义的方法,并维护了对聚合对象的引用,用于遍历聚合对象中的元素。
 聚合(Aggregate):聚合是一个接口或抽象类,定义了创建迭代器的方法,该方法返回一个对应的具体迭代器对象。
 具体聚合(Concrete Aggregate):具体聚合是聚合接口的具体实现,它实现了创建迭代器的方法,返回对应的具体迭代器对象。

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

// 聚合接口
interface Aggregate {
    Iterator createIterator();
}

// 具体迭代器类
class ConcreteIterator implements Iterator {
    private String[] elements;
    private int position;

    public ConcreteIterator(String[] elements) {
        this.elements = elements;
        this.position = 0;
    }

    @Override
    public boolean hasNext() {
        return position < elements.length;
    }

    @Override
    public Object next() {
        if (hasNext()) {
            String element = elements[position];
            position++;
            return element;
        }
        return null;
    }
}

// 具体聚合类
class ConcreteAggregate implements Aggregate {
    private String[] elements;

    public ConcreteAggregate(String[] elements) {
        this.elements = elements;
    }

    @Override
    public Iterator createIterator() { // 该方法用于创建迭代器对象
        return new ConcreteIterator(elements);
    }
}

// 客户端
public class Main {
    public static void main(String[] args) {
        String[] elements = { "Element 1", "Element 2", "Element 3", "Element 4" };
        Aggregate aggregate = new ConcreteAggregate(elements);
        Iterator iterator = aggregate.createIterator();

        while (iterator.hasNext()) {
            Object element = iterator.next();
            System.out.println("Element: " + element);
        }
    }
}

3.9 访问者模式

 访问者模式允许在不修改现有对象结构的情况下,定义新的操作(访问者)并应用于这些对象上。
 访问者(Visitor):访问者是一个接口或抽象类,定义了对不同类型的对象进行访问的方法,每个方法对应一种元素类型。
 具体访问者(Concrete Visitor):具体访问者是访问者接口的具体实现,实现了对元素类型的具体操作。
 元素(Element):元素是一个接口或抽象类,定义了接受访问者对象的方法,通常是 accept() 方法。
 具体元素(Concrete Element):具体元素是元素接口的具体实现,实现了 accept() 方法,并在其中调用访问者对象的相应方法。
 对象结构(Object Structure):对象结构是一个集合,它包含了一组元素对象,可以是数组、列表、树等。

// 访问者接口,比如人(主人、客人)喂宠物(猫、狗)
interface Visitor {
    void visit(ConcreteElementA element);
    void visit(ConcreteElementB element);
}

// 具体访问者类
class ConcreteVisitor implements Visitor {
    @Override
    public void visit(ConcreteElementA element) {
        System.out.println("Visited ConcreteElementA");
    }

    @Override
    public void visit(ConcreteElementB element) {
        System.out.println("Visited ConcreteElementB");
    }
}

// 元素接口
interface Element {
    void accept(Visitor visitor);
}

// 具体元素类
class ConcreteElementA implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

class ConcreteElementB implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

// 对象结构类
class ObjectStructure {
    private List<Element> elements = new ArrayList<>();

    public void addElement(Element element) {
        elements.add(element);
    }

    public void accept(Visitor visitor) {
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

// 客户端
public class Main {
    public static void main(String[] args) {
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.addElement(new ConcreteElementA());
        objectStructure.addElement(new ConcreteElementB());

        Visitor visitor = new ConcreteVisitor();
        objectStructure.accept(visitor);
    }
}

3.10 备忘录模式

 备忘录模式用于捕获和恢复对象的内部状态,而不破坏对象的封装性。备忘录模式通过将对象的状态保存在备忘录对象中,以便在需要时可以还原到之前的状态。
 发起人(Originator):发起人是需要保存和恢复状态的对象。它包含了要保存的状态,并提供了创建备忘录和从备忘录恢复状态的方法
 备忘录(Memento):备忘录是保存发起人对象内部状态的对象。它可以存储一部分或全部发起人对象的状态信息。
 管理者(Caretaker):管理者负责保存备忘录对象,并在需要时将备忘录对象交给发起人进行状态恢复。它可以管理多个备忘录对象,也可以对备忘录进行操作,例如存储、检索等。

// 备忘录类
class Memento {
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }
}

// 发起人类
class Originator {
    private String state;

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

    public String getState() {
        return state;
    }

    public Memento createMemento() {
        return new Memento(state);
    }

    public void restoreFromMemento(Memento memento) {
        state = memento.getState();
    }
}

// 管理者类
class Caretaker {
    private Memento memento;

    public void saveMemento(Memento memento) {
        this.memento = memento;
    }

    public Memento retrieveMemento() {
        return memento;
    }
}

// 客户端
public class Main {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        originator.setState("State 1");
        System.out.println("Current State: " + originator.getState());

        // 保存状态
        caretaker.saveMemento(originator.createMemento());

        originator.setState("State 2");
        System.out.println("Current State: " + originator.getState());

        // 恢复状态
        originator.restoreFromMemento(caretaker.retrieveMemento());
        System.out.println("Current State: " + originator.getState());
    }
}

3.11 解释器模式

 解释器模式定义了一种语言文法的表示,并为文法中的每个规则定义一个解释器,来解释并执行特定的任务。它适用于需要解析和执行特定语言或规则的场景。
 抽象表达式(AbstractExpression):抽象表达式是一个接口或抽象类,定义了解释器的接口,其中包含了解释器的抽象方法。
 终结符表达式(TerminalExpression):终结符表达式是抽象表达式的具体实现,它实现了解释器的抽象方法。终结符表达式表示语言中的基本单元,不能再进行进一步的解释。
 非终结符表达式(NonterminalExpression):非终结符表达式是抽象表达式的具体实现,它实现了解释器的抽象方法。非终结符表达式表示语言中的复合规则,可以通过组合其他表达式来进行解释。
 上下文(Context):上下文是解释器模式的执行环境,它包含了解释器需要的一些全局信息或状态。

// 抽象表达式类
interface Expression {
    boolean interpret(String context);
}

// 终结符表达式类
class TerminalExpression implements Expression {
    private String data;

    public TerminalExpression(String data) {
        this.data = data;
    }

    @Override
    public boolean interpret(String context) {
        return context.contains(data);
    }
}

// 非终结符表达式类
class OrExpression implements Expression {
    private Expression expr1;
    private Expression expr2;

    public OrExpression(Expression expr1, Expression expr2) {
        this.expr1 = expr1;
        this.expr2 = expr2;
    }

    @Override
    public boolean interpret(String context) {
        return expr1.interpret(context) || expr2.interpret(context);
    }
}

// 上下文类
class Context {
    private String data;

    public Context(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }
}

// 客户端
public class Main {
    public static void main(String[] args) {
        Expression john = new TerminalExpression("John");
        Expression emily = new TerminalExpression("Emily");
        Expression orExpression = new OrExpression(john, emily);

        Context context1 = new Context("John likes soccer");
        System.out.println(orExpression.interpret(context1.getData()));  // Output: true

        Context context2 = new Context("Emily likes basketball");
        System.out.println(orExpression.interpret(context2.getData()));  // Output: true

        Context context3 = new Context("Peter likes tennis");
        System.out.println(orExpression.interpret(context3.getData()));  // Output: false
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值