【23种设计模式应用场景汇总】

23种设计模式应用场景汇总


【23种设计模式应用场景汇总】_第1张图片

设计模式是一种在软件开发中解决特定问题的通用解决方案。下面我将尝试将23种设计模式融入到一个场景中:
假设我们正在开发一个在线购物系统,我们可以使用以下设计模式:

  • 1. 工厂方法模式:当用户在网站上下订单时,我们可以使用工厂方法模式来创建订单对象,根据用户选择的商品类型,使用不同的工厂来创建相应的订单对象。

分为:工厂模式分为:简单工厂、工厂方法、抽象工厂。
1、简单工厂通过参数决定创建哪个实例、
2、工厂方法将工厂、产品提出抽象接口、每一种产品对应一个工厂,最后根据用户的参数,使用不同的工厂创建不同的产品实例。
3、抽象工厂:是一个工厂创建一系列产品(比如windos上的GUI组件:windows版本的按钮、文本框、选择按钮等,是与linux或MacOs下的不同)。产品1(A系列产品1、B系列产品2),产品2(A系统产品2、B系列产品2),工厂(A系列工厂、B系列工厂),A工厂就会创建A系列产品1、A系列产品2;B工厂创建B系列产品1、B系列产品2.

  • 2. 单例模式:我们可以使用单例模式来确保系统中的购物车对象只有一个实例,以确保用户在整个会话期间都使用同一个购物车。

懒汉式和饿汉式。五种,最重要的是线程安全。

 // 1. 饿汉式(静态常量初始化)
   public class SingletonHungry {
       // 类加载时就完成初始化
       private static final SingletonHungry INSTANCE = new SingletonHungry();

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

       // 提供公共的静态方法获取实例
       public static SingletonHungry getInstance() {
           return INSTANCE;
       }
   }
// 特点:线程安全,调用效率高,但不能延时加载(类加载时立即初始化)。

// 2. 懒汉式(线程不安全)
// 特点:单例对象在第一次被使用时才初始化,实现了延时加载,但不是线程安全的。
   public class SingletonLazyUnsafe {
       private static SingletonLazyUnsafe instance;

       private SingletonLazyUnsafe() {}

       public static SingletonLazyUnsafe getInstance() {
           if (instance == null) {
               instance = new SingletonLazyUnsafe();
           }
           return instance;
       }
   }
 
 // 3. 懒汉式(线程安全,同步方法)
  public class SingletonLazySafeSync {
     private static SingletonLazySafeSync instance;

     private SingletonLazySafeSync() {}

     public static synchronized SingletonLazySafeSync getInstance() {
         if (instance == null) {
             instance = new SingletonLazySafeSync();
         }
         return instance;
     }
 }
 // 特点:通过在getInstance方法上添加synchronized关键字实现线程安全,
 // 但是由于每次获取实例都需要同步,导致性能不高 。

// 4. 双重检查锁定(DCL,Double-Checked Locking)
public class SingletonLazyDCL {
     private volatile static SingletonLazyDCL instance;

     private SingletonLazyDCL() {}

     public static SingletonLazyDCL getInstance() {
         if (instance == null) {
             synchronized (SingletonLazyDCL.class) {
                 if (instance == null) {
                     instance = new SingletonLazyDCL();
                 }
             }
         }
         return instance;
     }
 }
 // 特点:结合了懒加载和线程安全,只有在实例为null且需要创建时才进行同步,提高了性能。
 //  但在早期JVM中可能存在指令重排问题,volatile关键字可以解决这个问题。

// 5. 静态内部类方式
public class SingletonInnerClass {
     private SingletonInnerClass() {}

     private static class SingletonHolder {
         private static final SingletonInnerClass INSTANCE = new SingletonInnerClass();
     }

     public static SingletonInnerClass getInstance() {
         return SingletonHolder.INSTANCE;
     }
 }
// 特点:利用类加载机制确保线程安全,既实现了懒加载,又保证了高效率。
//        同时也能防止反射和反序列化攻击破坏单例性。

// 6. 枚举方式
 public enum SingletonEnum {
     INSTANCE;

     public void doSomething() {
         // 单例的相关操作
     }
 }
// 特点:这是Effective Java作者Joshua Bloch推荐的方式,不仅能避免多线程同步问题,
//      而且还能防止反序列化重新创建新的对象,绝对防止多次实例化。不过这种方式不能延时加载。  
  • 3. 观察者模式:当用户下订单时,我们可以使用观察者模式通知库存管理系统和仓库系统更新库存。这样,一旦有商品被下单,其他系统就会及时得到通知。

观察者模式

  1. java中提供了类Observable,只需要继承此类即可将子类变成Subject(被观察者)
  2. 被观察者持有观察者的引用,所以subject的状态发生变化后,就可以通知到观察者
  3. 观察者需要实现Observer, 重写update方法。
  • 4. 策略模式:在计算订单总价时,我们可以根据用户的会员等级或者促销活动来选择不同的计价策略,这就是策略模式的应用。
  1. 具体的角色有: strategy(一个抽象类或接口)
  2. 具体策略ConcreteStrategy(提供不同的算法)
  3. 环境角色:context 持有策略的引用,负责根据在运行时的需求选择并设置具体的策略对象。与客户端进行交互,通过使用策略对象执行相应的操作或计算。
  • 5. 适配器模式:当我们需要将外部支付f接口整合到系统中时,我们可能需要使用适配器模式来将外部接口适配成我们系统内部的统一接口。

三个角色:Target目标类、源Adaptee、适配器Adapter

  1. 目标角色定义了客户端所期待的接口,也就是客户程序需要调用的方法。它是适配器要转换到的目标接口
  2. 源角色是现有的接口或实现类,它拥有需要被适配的功能,但其接口与目标不兼容。
  3. 适配器角色实现了目标接口,并持有对源对象的引用,负责将源对象的接口转换为与目标接口兼容的形式。
    适配器模式的关键在于,通过创建一个适配器类来解决现有类与期望接口之间的不匹配问题,使得原本由于接口不兼容而无法协同工作的两个系统可以协同工作。

分类: 在具体实现中,适配器模式可以分为两种类型

  • 类适配器:适配器类继承自源角色,并实现目标接口,所以适配器既可以调用源角色的方法,又能提供目标接口要求的方法。
  • 对象适配器:适配器类实现目标接口,并持有一个源对象实例作为成员变量,通过调用源对象的方法来完成目标接口的实现
  • 6. 装饰者模式:如果我们需要在订单中加入礼品包装、贺卡等功能,可以使用装饰者模式动态地为订单对象添加额外的功能。

装饰者功能

  1. 扩展功能:当需要向现有的类中添加新的行为或职责时,尤其是不能直接修改原始类的源代码的情况下,可以使用装饰者模式动态地将新功能附加到对象上。
  2. 灵活组合出各种特性的对象:通过不同的装饰者排列组合,可以构建出不同特性的对象,实现多种功能的可插拔式组合。
  3. 装饰者对象与被装饰的对象具有相同的超类型,客户端程序无需知道是否进行了装饰以及如何装饰的细节,只需面向统一的接口进行操作即可。

角色

  1. component:定义了一个对象接口,可以给这些对象动态添加职责。
  2. ConcreteComponent:具体的原始组件对象,实现了Component接口。
  3. Decorator: 抽象装饰者类,继承自Component,从外类扩展Component类的功能,维持了与Component相同的接口。
  4. ConcreteDecorator:具体装饰类,实现了Decorator接口,并维持对Component对象的引用,在其方法中既可以调用原始对象的方法,也可以增加额外的操作。

代码演示如下:

// 首先,我们定义一个基本的饮料接口:
public interface Beverage {
    String getDescription();
    double cost();
}
// 接着,创建一个具体的饮料实现,比如普通咖啡(PlainCoffee):
public class PlainCoffee implements Beverage {
    @Override
    public String getDescription() {
        return "Plain Coffee";
    }

    @Override
    public double cost() {
        return 1.0;
    }
}
// 然后,我们创建装饰者抽象类:
public abstract class CondimentDecorator implements Beverage {
    protected Beverage beverage;

    public CondimentDecorator(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ", " + getCondimentDescription();
    }

    // 子类需要重写这个方法,提供附加描述信息
    protected abstract String getCondimentDescription();

    // 费用通常会叠加,但也可以根据具体装饰者的行为进行调整
    @Override
    public double cost() {
        return beverage.cost() + getCondimentCost();
    }

    // 子类需要重写这个方法,提供附加成本
    protected abstract double getCondimentCost();
}

// 接下来,我们创建几个具体的装饰者,例如糖和牛奶:
public class SugarDecorator extends CondimentDecorator {
    public SugarDecorator(Beverage beverage) {
        super(beverage);
    }

    @Override
    protected String getCondimentDescription() {
        return "with Sugar";
    }

    @Override
    protected double getCondimentCost() {
        return 0.25;
    }
}

public class MilkDecorator extends CondimentDecorator {
    public MilkDecorator(Beverage beverage) {
        super(beverage);
    }

    @Override
    protected String getCondimentDescription() {
        return "with Milk";
    }

    @Override
    protected double getCondimentCost() {
        return 0.5;
    }
}
// 现在我们可以这样使用装饰者模式:
public class Main {
    public static void main(String[] args) {
        Beverage plainCoffee = new PlainCoffee();
        System.out.println(plainCoffee.getDescription() + " - $" + plainCoffee.cost());

        Beverage coffeeWithSugar = new SugarDecorator(plainCoffee);
        System.out.println(coffeeWithSugar.getDescription() + " - $" + coffeeWithSugar.cost());

        Beverage coffeeWithMilkAndSugar = new MilkDecorator(coffeeWithSugar);
        System.out.println(coffeeWithMilkAndSugar.getDescription() + " - $" + coffeeWithMilkAndSugar.cost());
    }
}
// 运行上述代码,输出将是:
/**
* Plain Coffee - $1.0
* Plain Coffee, with Sugar - $1.25
* Plain Coffee, with Sugar, with Milk - $1.75
*/
// 总结:通过装饰者模式,我们能够动态地向咖啡中添加糖和牛奶,并且它们的成本也随之增加,
// 而无需修改原始的PlainCoffee类。
  • 7. 命令模式:在处理用户的退货请求时,我们可以使用命令模式将用户的退货请求封装成命令对象,然后由相应的命令对象来执行具体的退货操作。

角色分类:

  1. 调用者/请求者(Invoker)
  2. 抽象命令(Command)和具体命令(concreteCommand)
  3. 接收者(Receiver)
  4. 客户端Client


调用链:       客户端 ——> 调用者 ——> 命令——> 接受者

  • 8. 模板方法模式:在生成订单报告时,我们可以使用模板方法模式定义生成报告的流程,然后在具体的报告生成类中实现具体的步骤。

角色

  1. 抽象类(Abstract Class/Template Class)
    * 定义了一个或多个抽象操作方法,用于子类去实现。同时定义了一个或多个具体方法(通常包括一个或多个框架方法),这些方法可以是一个完整的算法骨架,包含了整个算法的固定步骤。
  2. 具体子类(concrete subClass)
    实现了抽象类中所声 明的抽象操作。每个子类提供了一种不同的算法实现方式。
    子类在实现抽象方法时填充模版方法预留的"空洞",从而完成特定的业务逻辑。

功能

  • 模版方法模式通过将不变的行为(即模版方法)放在抽象类中,并将可变的行为(即抽象方法)留给子类去实现,实现了代码复用和对算法结构的控制。子类可以在不改变算法整体结构的前提下,重新定义部分步骤,以适应不同的应用场景。
  • 9. 原型模式:在系统中有一些商品是定制化的,我们可以使用原型模式来克隆商品对象,以便快速创建定制化商品的副本。

角色分类:

  1. 抽象原型类(prototype Interface/Abstract Prototype class)
    定义了一个克隆自身的接口,通常包含一个clone()方法,它是所有具体原型类必须实现的方法。
  2. 具体原型类(Concrete Prototype Class)
    实现了抽象原型类所声明的clone()方法,该方法可以创建并返回一个新的对象实例,这个新实例是当前对象的一个深拷贝或者浅拷贝。
    具体原型类包含了定义对象状态的所有必要属性和行为。
  3. 客户端(Client)
    创建并使用具体原型类的对象,通过调用原型对象的clone()方法来复制出新的对象实例,而不是直接通过new关键字创建新对象。
  • 10. 抽象工厂模式:如果我们的系统需要支持多个不同类型的支付方式(比如信用卡、支付宝、微信支付等),我们可以使用抽象工厂模式来创建不同支付方式的工厂,从而实现一个统一的支付接口。
  • 11. 建造者模式:当用户在网站上定制礼篮时,我们可以使用建造者模式来创建复杂的礼篮对象,将其构建过程与表示分离,使得构建过程可以创建不同的表示。

角色:

  1. 抽象建造者:
    – 定义了一个创建产品的接口,声明了一系列用于构建产品对象的方法。这些方法通常按特定的顺序调用以逐步构造整个产品对象。
  2. 具体建造者:
    – 实现了抽象建造者接口,并提供构造和装配产品的各个部件的具体实现。在建造过程完成后,它还提供了获取最终产品的接口或方法。
  3. 产品:
    – 是建造者模式所要创建的对象类型。可以是一个复杂的对象,包含多个属性或者子组件。
  4. 导演者/指挥者(Director):
    – 负责控制建造过程,协调各个步骤的执行顺序。它可以独立于具体建造者角色而变化,不依赖于具体的构建细节。
    指挥者 ——> 建造者 ——> 产品
/**
 示例代码
 作者: LeKu_yuan
*/
// 1. 抽象建造者
public abstract class AbstractComputerBuilder {
    protected Computer computer = new Computer();

    public abstract void buildCPU();
    public abstract void buildMemory();
    public abstract void buildHardDrive();

    // 返回最终产品
    public Computer getComputer() {
        return computer;
    }
}

// 2. 具体建造者
public class HighPerformanceComputerBuilder extends AbstractComputerBuilder {
    @Override
    public void buildCPU() {
        computer.setCpu("Intel Core i9");
    }

    @Override
    public void buildMemory() {
        computer.setMemory("64GB DDR5 RAM");
    }

    @Override
    public void buildHardDrive() {
        computer.setHardDrive("2TB SSD");
    }
}

// 3. 产品
public class Computer {
    private String cpu;
    private String memory;
    private String hardDrive;

    public String getCpu() {
        return cpu;
    }

    public void setCpu(String cpu) {
        this.cpu = cpu;
    }

    public String getMemory() {
        return memory;
    }

    public void setMemory(String memory) {
        this.memory = memory;
    }

    public String getHardDrive() {
        return hardDrive;
    }

    public void setHardDrive(String hardDrive) {
        this.hardDrive = hardDrive;
    }

    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", memory='" + memory + '\'' +
                ", hardDrive='" + hardDrive + '\'' +
                '}';
    }
}

// (4. 可选角色)导演者/指挥者
public class Director {
    private AbstractComputerBuilder builder;

    public Director(AbstractComputerBuilder builder) {
        this.builder = builder;
    }

    public Computer constructComputer() {
        builder.buildCPU();
        builder.buildMemory();
        builder.buildHardDrive();
        return builder.getComputer();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Director director = new Director(new HighPerformanceComputerBuilder());
        Computer highPerformanceComputer = director.constructComputer();
        System.out.println(highPerformanceComputer);
    }
}

  • 12. 状态模式:在订单处理流程中,订单可能会经历多个状态(比如待支付、已支付、已发货、已签收等),我们可以使用状态模式来管理订单的状态转换,使状态转换更加清晰和可维护。

角色:

  1. 抽象状态类:定义所有具体状态角色需要实现的接口或抽象类
  2. 具体状态类:实现抽象状态角色所定义的接口,即为系统可能处于的各种状态提供具体的实现。
  3. 上下文:也称为上下文,是使用状态模式的类,它维护一个指向当前状态对象的引用

abstract class TrafficLightState {
   protected TrafficLight trafficLight;
   public void setTrafficLight(TrafficLight trafficLight) {
       this.trafficLight = trafficLight;
   }
   
   // 抽象方法,由具体状态实现
   public abstract void turnOn();
   public abstract void turnOff();
   public abstract void changeToNextState();
   
}

 // 具体状态角色(Concrete State)
class RedLightState extends TrafficLightState {
    @Override
    public void turnOn() {
        System.out.println("红灯亮起");
    }

    @Override
    public void turnOff() {
        System.out.println("红灯熄灭");
    }
    
    @Override
    public void changeToNextState() {
        trafficLight.setState(trafficLight.getYellowLightState());
    }
}

class YellowLightState extends TrafficLightState {
   @Override
   public void turnOn() {
       System.out.println("黄灯亮起");
   }

   @Override
   public void turnOff() {
       System.out.println("黄灯熄灭");
   }

   @Override
   public void changeToNextState() {
       trafficLight.setState(trafficLight.getGreenLightState());
   }
}

class GreenLightState extends TrafficLightState {
   @Override
   public void turnOn() {
       System.out.println("绿灯亮起");
   }

   @Override
   public void turnOff() {
       System.out.println("绿灯熄灭");
   }

   @Override
   public void changeToNextState() {
       trafficLight.setState(trafficLight.getRedLightState());
   }
}

 // 环境角色(Context)
public class TrafficLight {
   private TrafficLightState currentState;

   public TrafficLight() {
       currentState = new RedLightState();
       currentState.setTrafficLight(this);
   }

   public TrafficLightState getRedLightState() {
       return new RedLightState();
   }

   public TrafficLightState getYellowLightState() {
       return new YellowLightState();
   }

   public TrafficLightState getGreenLightState() {
       return new GreenLightState();
   }

   public void setState(TrafficLightState state) {
       currentState = state;
       currentState.turnOn();
   }

   public void changeLights() {
       currentState.changeToNextState();
   }
}

// 使用示例
public class Main {
   public static void main(String[] args) {
       TrafficLight trafficLight = new TrafficLight();
       trafficLight.changeLights();  // 输出:红灯亮起
       trafficLight.changeLights();  // 输出:黄灯亮起
       trafficLight.changeLights();  // 输出:绿灯亮起
       trafficLight.changeLights();  // 输出:红灯亮起
   }
}
  • 13. 桥接模式:如果我们需要在不同的平台上展示商品信息(比如网站、移动端、微信小程序等),我们可以使用桥接模式平台和商品信息的展示进行解耦,从而让它们可以独立地变化

桥接模式(Bridge Pattern)是一种结构设计模式,它将抽象部分与它的实现部分分离,使它们都可以独立地变化。


角色

  1. 抽象化角色(Abstraction): 这是抽象类,定义了抽象接口,维护一个对实现化角色的引用。与客户端进行交互
  2. 扩展抽象化角色(Refined Abstraction): 这是抽象化角色的子类,可以提供额外的功能和方法,或者修改从抽象化继承的方法行为,但仍然包含对实现化角色的引用。
  3. 实现化角色(Implementor):
    这是一个接口或抽象类,定义了实现化角色需要实现的一组接口方法。
    实现化角色不依赖于抽象化角色,它定义了实现功能的具体结构和算法
  4. 具体实现化角色(Concrete Implementor)
    这是实现化角色的具体实现类,实现了接口或抽象类定义的所有方法,为抽象化角色提供了具体的实现方案。

总结: 将两个变化的因素分割开,利用笛卡尔积使其组合,而不是创建笛卡尔积个类模版。


例子: 比如形状和颜色,不同的形状需要不同的颜色,这个可以分开。

//  **代码演示**:
// 实现化角色(Implementor)
interface ColorStrategy {
    void applyColor();
}

// 具体实现化角色(Concrete Implementor)
class RedColorStrategy implements ColorStrategy {
    @Override
    public void applyColor() {
        System.out.println("应用红色填充");
    }
}

class GreenColorStrategy implements ColorStrategy {
    @Override
    public void applyColor() {
        System.out.println("应用绿色填充");
    }
}

// 抽象化角色(Abstraction)
abstract class Shape {
    protected ColorStrategy color;

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

    public abstract void draw();

    public void setColor(ColorStrategy color) {
        this.color = color;
    }
}

// 扩展抽象化角色(Refined Abstraction)
class Circle extends Shape {
    public Circle(ColorStrategy color) {
        super(color);
    }

    @Override
    public void draw() {
        System.out.println("绘制圆形...");
        color.applyColor(); // 应用颜色填充策略
    }
}

class Square extends Shape {
    public Square(ColorStrategy color) {
        super(color);
    }

    @Override
    public void draw() {
        System.out.println("绘制正方形...");
        color.applyColor(); // 应用颜色填充策略
    }
}

// 使用示例
public class BridgePatternDemo {
    public static void main(String[] args) {
        Shape circle1 = new Circle(new RedColorStrategy());
        Shape square1 = new Square(new GreenColorStrategy());

        circle1.draw();  // 输出:绘制圆形... 应用红色填充
        square1.draw();   // 输出:绘制正方形... 应用绿色填充

        circle1.setColor(new GreenColorStrategy());
        square1.setColor(new RedColorStrategy());

        circle1.draw();  // 输出:绘制圆形... 应用绿色填充
        square1.draw();   // 输出:绘制正方形... 应用红色填充
    }
}

  • 14. 组合模式:在管理商品分类树的时候,我们可以使用组合模式来表示商品分类和子分类的层次结构,以便对整个分类树进行统一的操作。

角色

  1. Component(抽象构件):定义了所有组件(包括叶子组件和容器组件)共享的接口。这些方法可能包括添加、删除子组件,以及一些针对整个组件树的通用操作。
  2. Leaf(叶子构件):表示组合结构中的叶节点对象,其没有子节点。实现了 Component 接口,并提供了相应的业务逻辑。
  3. Composite(容器构件):定义了有子节点的组合对象,同样实现 Component 接口,并提供管理子组件的方法。容器构件可以包含零个或多个其他 Component 对象。

总结

  • 通过组合模式的应用,可以让用户对单个对象和复合对象的使用具有统一性和一致性,同时能够灵活地遍历整个结构并对每个元素进行相同的操作处理。
// 抽象构件(Component)
interface FileSystemObject {
    void add(FileSystemObject obj);
    void remove(FileSystemObject obj);
    void display(int depth);
}

// 叶子构件(Leaf)
class File implements FileSystemObject {
    private String name;

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

    @Override
    public void add(FileSystemObject obj) {
        throw new UnsupportedOperationException("Files cannot contain other objects");
    }

    @Override
    public void remove(FileSystemObject obj) {
        throw new UnsupportedOperationException("Files cannot contain other objects");
    }

    @Override
    public void display(int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);
    }
}

// 容器构件(Composite)
class Directory implements FileSystemObject {
    private List<FileSystemObject> children;
    private String name;

    public Directory(String name) {
        this.name = name;
        this.children = new ArrayList<>();
    }

    @Override
    public void add(FileSystemObject obj) {
        children.add(obj);
    }

    @Override
    public void remove(FileSystemObject obj) {
        children.remove(obj);
    }

    @Override
    public void display(int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);

        for (FileSystemObject child : children) {
            child.display(depth + 1);
        }
    }
}

// 使用示例
public class CompositePatternDemo {
    public static void main(String[] args) {
        Directory root = new Directory("Root");
        Directory dir1 = new Directory("Dir1");
        Directory dir2 = new Directory("Dir2");
        File file1 = new File("File1.txt");
        File file2 = new File("File2.txt");

        root.add(dir1);
        root.add(dir2);
        dir1.add(file1);
        dir2.add(file2);

        root.display(0);
    }
}
  • 15. 迭代器模式:当需要遍历购物车中的商品列表时,我们可以使用迭代器模式来提供一种统一的方式来遍历不同类型的购物车。
  • 16. 访问者模式:如果需要对不同类型的商品进行不同的操作(比如打印、计算价格等),我们可以使用访问者模式来实现对商品的不同操作,而不需要修改商品类的代码。

角色

  1. Element(元素接口):声明接受访问者对象的 accept() 方法,这是所有需要被访问的对象必须实现的接口。
  2. ConcreteElement(具体元素):实现了 Element 接口的具体元素类,它们可以是多种不同的业务>对象,每个类都提供 accept() 方法,并且可能有各自不同的内部结构和状态。
  3. Visitor(访问者接口):声明了对每一个 ConcreteElement 的访问操作,通常以方法的形式存在,每一个方法对应一种具体的元素类型。
  4. ConcreteVisitor(具体访问者):实现了 Visitor 接口的具体访问者类,为每个 visit() 方法提供了具体的实现,从而定义了针对不同元素的操作逻辑。
  5. ObjectStructure(对象结构):能够存储并遍历元素集合,它可以是一个容器或者一个复合对象,提供一个方法来允许访问者访问它的元素。

总结

  • 使用访问者模式的一个典型场景是在一个对象结构中执行某种特定操作,但又不想让这些操作侵入到各个元素类中。例如,在编译器的不同阶段(语法分析、语义分析等),对AST(抽象语法树)节点进行操作时,就可以采用访问者模式。
  • 数据结构与操作分离、避免操作入侵数据
// Element 接口
interface Animal {
    void accept(AnimalOperation operation);
}

// ConcreteElement 类
class Lion implements Animal {
    @Override
    public void accept(AnimalOperation operation) {
        operation.visit(this);
    }
    
    // 其他 Lion 类相关的方法...
}

class Elephant implements Animal {
    @Override
    public void accept(AnimalOperation operation) {
        operation.visit(this);
    }
    
    // 其他 Elephant 类相关的方法...
}

// Visitor 接口
interface AnimalOperation {
    void visit(Lion lion);
    void visit(Elephant elephant);
}

// ConcreteVisitor 类
class FeedVisitor implements AnimalOperation {
    @Override
    public void visit(Lion lion) {
        System.out.println("Feeding the lion");
    }

    @Override
    public void visit(Elephant elephant) {
        System.out.println("Feeding the elephant");
    }
}

class CleanVisitor implements AnimalOperation {
    @Override
    public void visit(Lion lion) {
        System.out.println("Cleaning the lion's habitat");
    }

    @Override
    public void visit(Elephant elephant) {
        System.out.println("Cleaning the elephant's habitat");
    }
}

// ObjectStructure
class Zoo {
    private List<Animal> animals;

    public void addAnimal(Animal animal) {
        animals.add(animal);
    }

    public void performOperation(AnimalOperation operation) {
        for (Animal animal : animals) {
            animal.accept(operation);
        }
    }
}

// 使用示例
public class VisitorPatternDemo {
    public static void main(String[] args) {
        Zoo zoo = new Zoo();
        zoo.addAnimal(new Lion());
        zoo.addAnimal(new Elephant());

        AnimalOperation feedVisitor = new FeedVisitor();
        zoo.performOperation(feedVisitor); 

        AnimalOperation cleanVisitor = new CleanVisitor();
        zoo.performOperation(cleanVisitor);
    }
}

  • 17. 备忘录模式:在用户进行购物车操作时,我们可以使用备忘录模式来保存购物车的状态,以便用户可以在需要时恢复到之前的状态。

备忘操作需要:操作人、备忘的对象(内容、数据)、备忘薄


角色

  1. Originator(发起对象)
  2. Memento(备忘录)
  3. Caretaker(负责对象)

好处:
利用其他扩展恢复数据,而不是增加本身的复杂性。

  • 18. 解释器模式:如果我们需要实现一些复杂的促销规则或者查询条件,可以使用解释器模式来定义一个解释器,用于解释和执行这些规则或者条件。

角色

  1. AbstractExpression(抽象表达式):
    这是所有具体表达式的基类或者接口,声明了一个抽象的解释方法 interpret()。
    具体的解释操作由子类实现。
  2. TerminalExpression(终结符表达式):
    终结符表达式是文法中的原子元素,通常对应于文法中的基本符号或关键字。
    实现了 AbstractExpression 接口,并为特定的终结符提供了解释逻辑。
  3. NonterminalExpression(非终结符表达式):
    非终结符表达式通常是更复杂的表达式结构,它们可能包含其他表达式(包括终结符和非终结符)。
    同样实现了 AbstractExpression 接口,其解释方法可能根据包含的子表达式进行递归调用以完成复杂表达式的解释过程。
  4. Context(上下文环境):
    上下文环境角色包含了解释过程中需要的所有全局信息,比如变量、状态等,可以被各个表达式访问并影响它们的解释结果。
    有时上下文环境会作为参数传递给表达式解释方法,或者作为表达式对象的一个成员变量。
  • 19. 中介者模式:当订单系统、库存系统和物流系统之间需要进行协作时,我们可以使用中介者模式来将它们的交互行为封装到中介者对象中,从而降低系统中各个对象之间的耦合度。

预览

  • 中介者模式(Mediator Pattern)是一种行为设计模式,它通过引入一个中介对象来封装一系列的对*象交互
    角色
  1. AbstractMediator(抽象中介者):
    抽象中介者定义了与各个同事对象通信的接口,通常会包含一组方法,这些方法用于注册同事对象、通知同事对象以及处理它们之间的交互请求。
    抽象中介者定义了同事类之间交互的抽象规则,允许具体中介者来实现这些交互逻辑。
  2. ConcreteMediator(具体中介者):
    具体中介者实现了抽象中介者所声明的接口,并且负责协调和管理同事对象之间的交互。
    具体中介者了解并存储其同事对象的引用,并根据需要调用它们的方法以响应来自其他同事对象的请求或事件。
  3. Colleague(同事类):
    同事类是参与交互的对象,它们拥有对中介者的引用,并通过中介者进行相互通信,而不是直接与其他同事类通信。
    同事类可以将消息发送给中介者,并可能通过中介者接收到来自其他同事类的消息。
  • 20. 外观模式:当需要为客户端提供一个统一的接口来访问子系统中的一群接口时,可以使用外观模式来简化客户端与子系统之间的交互。

总结:

  • 外观模式(Facade Pattern)是一种结构设计模式,它为子系统中的一组接口提供了一个统一的、更高级别的接口。通过这个简化后的接口,客户端可以更方便地与子系统交互,而无需了解子系统的复杂内部实现细节。

角色

  1. Facade(外观类):
  • 提供了一个更高层次的接口,该接口对子系统中的多个类进行封装和整合。
    外观类通常包含对子系统对象的引用,并定义一组方法来调用这些子系统的功能。
    客户端只需要与外观类交互,就可以完成对整个子系统的操作。
  1. Subsystem Classes(子系统类):
  • 子系统类是实际负责执行任务的对象或组件,它们共同构成了子系统。
    子系统类通常有复杂的内部结构和相互依赖关系,但这些细节对于外观类以及使用外观类的客户端来>说都是透明的
// 子系统类(Subsystem Classes)
interface MediaPlayer {
    void play();
}

interface CDPlayer extends MediaPlayer {
    void insertCD(String cdTitle);
    void ejectCD();
}

interface Tuner {
    void turnOn();
    void setFrequency(int frequency);
    void turnOff();
}

interface Amplifier {
    void on();
    void off();
    void setStereoSound();
    void setSurroundSound();
    void setVolume(int level);
}

class CDPlayerImpl implements CDPlayer {
    @Override
    public void insertCD(String cdTitle) {
        // 实现插入CD的操作
    }

    @Override
    public void ejectCD() {
        // 实现弹出CD的操作
    }

    @Override
    public void play() {
        // 实现播放CD的操作
    }
    
    // 其他相关方法...
}

// 同样实现其他子系统类如TunerImpl、AmplifierImpl等...

// 外观类(Facade)
class HomeTheaterFacade {
    private CDPlayer cdPlayer;
    private Tuner tuner;
    private Amplifier amplifier;

    public HomeTheaterFacade(CDPlayer cdPlayer, Tuner tuner, Amplifier amplifier) {
        this.cdPlayer = cdPlayer;
        this.tuner = tuner;
        this.amplifier = amplifier;
    }

    public void playCD(String cdTitle) {
        cdPlayer.insertCD(cdTitle);
        cdPlayer.play();
        amplifier.on();
        amplifier.setStereoSound();
        tuner.turnOn();
        tuner.setFrequency(99.1);  // 设置FM调频频率
    }

    public void stop() {
        cdPlayer.stop();
        tuner.turnOff();
        amplifier.off();
    }

    // 其他组合操作方法...
}

// 示例用法
public class FacadePatternDemo {
    public static void main(String[] args) {
        CDPlayer cdPlayer = new CDPlayerImpl();
        Tuner tuner = new TunerImpl();
        Amplifier amplifier = new AmplifierImpl();

        HomeTheaterFacade homeTheater = new HomeTheaterFacade(cdPlayer, tuner, amplifier);

        homeTheater.playCD("My Favorite Album");  // 简单地调用一个方法即可启动整个音乐播放流程
    }
}
  • 21. 代理模式:在系统中,我们可以使用代理模式来控制对敏感信息的访问,比如用户的个人信息,可以通过代理对象来进行访问控制。

角色

  1. Subject 抽象主题角色:这是一个接口或者抽象类,声明了真实主题和代理主题共同的方法
  2. RealSubject(真实主题角色):也称为“被代理角色”,它是代理所代表的真实对象。
  3. Proxy(代理角色):
  • 代理实现了与真实主题相同的接口(即 Subject),并可以附加额外的功能,如预处理请求、延迟加载、权限控制等。
  • 代理维护对真实主题的引用,在适当时机调用真实主题的方法来执行实际任务。
  • 在某些情况下,代理可能会对客户端请求进行拦截、过滤或增强后转发给真实主题。
  1. Client(客户端)
  • 客户端通过 Subject 接口与代理或真实主题交互,无需关心与之交互的对象是代理还是真实主题。

总结

  • 代理模式的核心思想是通过引入代理对象来间接访问目标对象,从而在访问过程中添加额外的操作或控制。这种模式在软件开发中有广泛应用,比如数据库连接池、远程服务调用、缓存代理、日志记录代理、权限控制代理等等。
  • 关注一下JDK动态代理(基于反射)和CGLIB代理(基于字节码技术)
  • 22. 责任链模式:当系统中需要处理一系列的请求,并且每个请求可能由不同的处理者来处理时,可以使用责任链模式来实现请求的传递和处理。

角色

  1. 抽象处理这Handler:
    • 定义了一个处理请求的接口,通常包含一个或多个方法来处理请求。
    • 通常会定义一个setNextHandler()方法用于将下一个处理者对象链接起来形成链式结构,并且包含一个对下一个处理者的引用。
    • 可能还包含一个抽象的或通用的处理请求的方法,比如handleRequest(Request request)。
  2. ConcreteHandler(具体处理者)
    • 继承自抽象处理者并实现了处理请求的方法。
    • 每个具体处理者在其内部决定是否能够处理当前请求。如果可以处理,则执行相应的逻辑;如果不可以处理,则通过调用其内部持有的下一个处理者的相同方法,将请求传递给下一个节点。
  3. Request(请求):
    • 请求对象封装了客户端发出的具体请求信息,它会被沿着责任链传递
  4. Client(客户端)
    • 创建责任链,并向链中的第一个处理者提交请求
    • 客户端并不关心请求是如何被处理和在链中如何传递的,它只需要知道请求最终会被合适的处理者处理即可。
// 请求对象(Request)
class LeaveRequest {
    private String employeeName;
    private int leaveDays;

    public LeaveRequest(String employeeName, int leaveDays) {
        this.employeeName = employeeName;
        this.leaveDays = leaveDays;
    }

    // 其他获取属性的方法...

    @Override
    public String toString() {
        return "Leave Request from " + employeeName + " for " + leaveDays + " days";
    }
}

// 抽象处理者(Handler)
abstract class Approver {
    protected Approver nextApprover;  // 对下一个处理者的引用

    public void setNextApprover(Approver approver) {
        this.nextApprover = approver;
    }

    public abstract void processRequest(LeaveRequest request);
}

// 具体处理者(ConcreteHandler)
class Manager extends Approver {
    @Override
    public void processRequest(LeaveRequest request) {
        if (request.getLeaveDays() <= 3) {  // 假设经理可以审批3天以内的假期
            System.out.println("Manager approved the request: " + request);
        } else if (nextApprover != null) {
            nextApprover.processRequest(request);  // 将请求转发给上级领导
        } else {
            System.out.println("No one can approve this request.");
        }
    }
}

class Director extends Approver {
    @Override
    public void processRequest(LeaveRequest request) {
        if (request.getLeaveDays() <= 10) {  // 假设总监可以审批10天以内的假期
            System.out.println("Director approved the request: " + request);
        } else if (nextApprover != null) {
            nextApprover.processRequest(request);  // 转发给更高级别的领导
        } else {
            System.out.println("No one can approve this request.");
        }
    }
}

// 客户端(Client)
public class ChainOfResponsibilityDemo {
    public static void main(String[] args) {
        Manager manager = new Manager();
        Director director = new Director();

        manager.setNextApprover(director);  // 构建责任链

        LeaveRequest request1 = new LeaveRequest("Employee A", 2);
        LeaveRequest request2 = new LeaveRequest("Employee B", 5);
        LeaveRequest request3 = new LeaveRequest("Employee C", 15);

        manager.processRequest(request1);  // 经理审批
        manager.processRequest(request2);  // 经理不能审批,转给总监
        manager.processRequest(request3);  // 经理和总监都不能审批
    }
}
  • 23. 享元模式:电商系统通常需要管理大量商品,每个商品可能有多个属性和规格(比如颜色、尺码等),而这些属性和规格可能是可以共享的。

预览:

  • 享元模式(Flyweight Pattern)是一种结构型设计模式,其主要目的是通过共享已经存在的对象来大幅度减少创建大量相似对象所消耗的内存资源。

角色

  1. Flyweight 抽象享元类:
    • 定义了所有具体享元类需要实现的公共接口。这个接口通常包含了可以共享的部分状态和方法。
  2. ConcreteFlyweight具体享元类:
  3. UnsharedConcreteFlyweight 不可共享的享元类:
    • 在某些情况下,不是所有的享元都可以共享。这种类不参与共享池的管理,每个实例都包含独特的信息,不能被其他对象共享。
  4. FlyweightFactory 享元工厂: 负责创建和管理享元对象,确保合理的享元对象复用。
  5. Client:
    • 使用享元对象的外部状态,并通过享元工厂获取所需的具体享元对象。
    • 客户端并不直接创建具体的享元对象,而是通过享元工厂间接访问它们

你可能感兴趣的:(#,Java,设计模式,设计模式,java)