23种设计模式——GoF23

一、GoF23是什么?四大指导思想?

是软件开发的一种思维,一种态度,一种进步,一些解决方案
四大指导思想:可维护、可复用、可扩展、灵活性
23种设计模式:https://www.kuangstudy.com/bbs?uid=&from=&cid=&isrecommend=&searchKey=%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F&pageNo=2

二、OOP七大原则?

  1. 开闭原则(Open-Closed Principle):实体(类、模块、函数等)应该对扩展开放,对修改关闭,即需求变化时,应当通过扩展现有代码来实现新的功能,而不是直接修改已有的代码。
    • 尽量不修改原来代码的情况下进行扩展
    • 多态是关键
public class AreaCalculator {
  public double calculateTotalArea(Shape[] shapes) {
    double totalArea = 0;
    
    for (Shape shape : shapes) {
    //使用 instanceof 运算符来判断形状的类型去执行对应的面积计算逻辑
      if (shape instanceof Rectangle) {
        Rectangle rectangle = (Rectangle) shape;
        totalArea += rectangle.getWidth() * rectangle.getHeight();
      } else if (shape instanceof Circle) {
        Circle circle = (Circle) shape;
        totalArea += Math.PI * circle.getRadius() * circle.getRadius();
      }
      // 若要支持新的形状,只需添加一个新的条件分支即可.
      //如此,它遵循了开闭原则。通过扩展新的形状类型时只需添加对应的条件分支,并在该分支中实现新形状的面积计算逻辑,而不需要修改已有的代码

      // 例如添加 Triangle 形状的支持
      // } else if (shape instanceof Triangle) {
      //   Triangle triangle = (Triangle) shape;
      //   totalArea += 0.5 * triangle.getBase() * triangle.getHeight();
      // }
    }
    return totalArea;
  }
}

  1. 里氏替换原则 (Liskov Substitution Principle):继承必须确保超类所拥有的性质在子类中仍然成立
    • 子类对象必须能够替换掉父类对象且保持程序正确性
public class Rectangle {
  private double width;
  private double height;

  public Rectangle(double width, double height) {
    this.width = width;
    this.height = height;
  }

  public double getWidth() {
    return width;
  }

  public void setWidth(double width) {
    this.width = width;
  }

  public double getHeight() {
    return height;
  }

  public void setHeight(double height) {
    this.height = height;
  }

  public double calculateArea() {
    return width * height;
  }
}

//Rectangle 类代表矩形,Square 类代表正方形, 子类Square继承并重写了父类方法确保了宽高始终相等
//将子类 Square 对象替换成 父类Rectangle 对象,在 AreaCalculator 类中使用 Rectangle 数组来计算矩形的总面积,而无需关心是矩形还是正方形。如此,使用了里氏替换原则
public class Square extends Rectangle {
  public Square(double sideLength) {
    super(sideLength, sideLength);
  }

  @Override
  public void setWidth(double width) {
    super.setWidth(width);
    super.setHeight(width);
  }

  @Override
  public void setHeight(double height) {
    super.setWidth(height);
    super.setHeight(height);
  }
}

public class AreaCalculator {
  public double calculateTotalArea(Rectangle[] rectangles) {
    double totalArea = 0;
    for (Rectangle rectangle : rectangles) {
      totalArea += rectangle.calculateArea();
    }
    return totalArea;
  }
}

public class Main {
  public static void main(String[] args) {
    Rectangle[] rectangles = new Rectangle[] {
      new Rectangle(5, 3),
      new Square(2)
    };

    AreaCalculator calculator = new AreaCalculator();
    double totalArea = calculator.calculateTotalArea(rectangles);
    System.out.println("Total area: " + totalArea);
  }
}

  1. 依赖倒置原则 (Dependence Inversion Principle):要面向接口编程,不要面向实现编程。
    • 依赖抽象,而不是依赖具体,面对抽象编程
//MessageSender 接口定义发送消息的方法
public interface MessageSender {
  void sendMessage(String message);
}
//有两个具体实现类 EmailSender 和 SMSMessageSender 分别用于发送邮件和短信
public class EmailSender implements MessageSender {
  @Override
  public void sendMessage(String message) {
    System.out.println("Sending email: " + message);
    // 实际的发送邮件逻辑
  }
}

public class SMSMessageSender implements MessageSender {
  @Override
  public void sendMessage(String message) {
    System.out.println("Sending SMS: " + message);
    // 实际的发送短信逻辑
  }
}

//NotificationService 类是高层模块,负责执行通知发送逻辑,它通过构造函数接收一个 MessageSender 对象
//将接口 MessageSender 作为抽象层,实现低层模块(具体实现类)对高层模块(NotificationService)的解耦,达到在需要切换发送方式时,只需创建新的具体实现类并传递给 NotificationService 的构造函数即可,如此,利用了依赖倒置原则
public class NotificationService {
  private MessageSender messageSender;

  public NotificationService(MessageSender messageSender) {
    this.messageSender = messageSender;
  }

  public void sendNotification(String message) {
    // 执行通知发送逻辑
    messageSender.sendMessage(message);
  }
}

public class Main {
  public static void main(String[] args) {
    MessageSender emailSender = new EmailSender();
    NotificationService notificationService = new NotificationService(emailSender);
    notificationService.sendNotification("Hello, this is an email notification.");

    MessageSender smsSender = new SMSMessageSender();
    notificationService = new NotificationService(smsSender);
    notificationService.sendNotification("Hello, this is an SMS notification.");
  }
}

  1. 单一职责原则(Single Responsibility Principle):控制类的粒度大小、将对象解耦、提高其内聚性。实现高内聚、低耦合
    • 一个类的设计别太大,负责单一的职责
public class UserService {
  public void createUser(String username, String password) {
    // 创建用户逻辑
    // ...
  }
  
  public void deleteUser(String username) {
    // 删除用户逻辑
    // ...
  }
  
  public void updateUserPassword(String username, String newPassword) {
    // 更新用户密码逻辑
    // ...
  }
  
  public void sendEmailNotification(String username, String message) {
    // 发送邮件通知逻辑
    // ...
  }
  
  public void generateReport(String username) {
    // 生成报告逻辑
    // ...
  }
}

public class Main {
  public static void main(String[] args) {
    UserService userService = new UserService();
    userService.createUser("john", "password");
    userService.updateUserPassword("john", "newpassword");
    userService.sendEmailNotification("john", "Hello, John!");
  }
}

上面UserService 类,负责处理用户相关的操作。包含创建用户、删除用户、更新用户密码、发送邮件通知和生成报告等方法。利用单一职责原则,将 UserService 类拆分为多个类(如 UserCreationService、UserManagementService、NotificationService 和 ReportService ),每个类专注于一个特定的职责。

  1. 接口隔离原则 (Interface Segregation Principle):要为各个类建立它们需要的专用接口
    • 每个接口应该承担独立的角色,不敢自己不该干的事儿
    • 暴露最小接口
public interface Printer {
  void print(String document);
}

public class SimplePrinter implements Printer {
  @Override
  public void print(String document) {
    System.out.println("Printing document: " + document);
    // 执行打印逻辑
    // ...
  }
}

public class FaxMachine implements Printer {
  @Override
  public void print(String document) {
    System.out.println("Sending fax: " + document);
    // 执行发送传真逻辑
    // ...
  }
  
  public void receiveFax() {
    // 接收传真逻辑
    // ...
  }
}

public class Main {
  public static void main(String[] args) {
    Printer printer = new SimplePrinter();
    printer.print("Sample document");

    Printer faxMachine = new FaxMachine();
    faxMachine.print("Sample document");
    //faxMachine.receiveFax();  // 不再需要调用接收传真的方法
  }
}

上面Printer 接口有print 方法用于打印文档。SimplePrinter 类是该接口的一个具体实现类,负责执行简单的文档打印逻辑。FaxMachine 类也实现了 Printer 接口,并负责执行发送传真和接收传真的逻辑。通过将不同的打印方式(简单打印和传真)放在不同的类中,实现了接口隔离原则。使用者可以根据需要选择合适的实现类来进行打印操作,而不必依赖于不需要的方法。

在 Main 类中,我们创建了一个 SimplePrinter 对象,并调用其 print 方法来打印文档。然后,我们创建了一个 FaxMachine 对象,并调用其 print 方法来发送传真。由于不再需要调用接收传真的方法,因此我们注释掉了相关代码。

  1. 迪米特法则(Law Of Demeter):只与你的直接朋友交谈,不跟“陌生人”说话。也称为“最少知识原则”
    • 和其它类的耦合度降低
public class Teacher {
  private String name;
  
  public Teacher(String name) {
    this.name = name;
  }
  
  public String getName() {
    return name;
  }
}

public class Student {
  private String name;
  private Teacher teacher;
  
  public Student(String name, Teacher teacher) {
    this.name = name;
    this.teacher = teacher;
  }
  
  public String getName() {
    return name;
  }
  
  public String getTeacherName() {
    return teacher.getName();
  }
}

public class School {
  public void admitNewStudent(Student student) {
    System.out.println("New student admitted: " + student.getName());
  }
}

public class Main {
  public static void main(String[] args) {
    Teacher teacher = new Teacher("Mr. Smith");
    Student student = new Student("John", teacher);
    
    School school = new School();
    school.admitNewStudent(student);
    
    System.out.println("Student's teacher: " + student.getTeacherName());
  }
}

上面有三个类:Teacher、Student 和 School。Teacher 类表示教师,包含教师的姓名。
Student 类表示学生,包含学生的姓名和教师的引用。通过学生的 getTeacherName 方法,我们可以获取学生所属教师的姓名,但是学生本身并不知道如何获取教师的姓名,而是通过调用教师的 getName 方法来实现的。
School 类表示学校,包含一个 admitNewStudent 方法用于录取新学生。在该方法中,我们只关心学生的姓名,并不需要了解学生的其他细节。
在 Main 类中,我们创建了一个教师对象 teacher 和一个学生对象 student,并将教师对象作为参数传递给学生对象。然后,我们创建了一个学校对象 school,并调用其 admitNewStudent 方法来录取学生。最后,我们打印出学生所属教师的姓名。
如此,利用迪米特原则。每个类只与其直接的朋友(即紧密相关的类)进行交互,而不涉及其他不必要的类。学生类只与教师类进行交互,而不需要与学校类直接交互。

  1. 合成复用原则 (Composite/Aggregate Reuse Principle):尽量先使用组合或者聚合等关联关系来实现,其次才考虑继承关系。
    • 为了低耦合
    • 通过将现有的类组合起来创建新的功能,从而实现代码的复用和灵活性。
public interface Engine {
  void start();
}

public class ElectricEngine implements Engine {
  @Override
  public void start() {
    System.out.println("Electric engine starts");
    // 执行启动电动引擎逻辑
    // ...
  }
}

public class GasolineEngine implements Engine {
  @Override
  public void start() {
    System.out.println("Gasoline engine starts");
    // 执行启动汽油引擎逻辑
    // ...
  }
}

public class Car {
  private Engine engine;
  
  public Car(Engine engine) {
    this.engine = engine;
  }
  
  public void startEngine() {
    engine.start();
  }
}

public class Main {
  public static void main(String[] args) {
    Engine electricEngine = new ElectricEngine();
    Car electricCar = new Car(electricEngine);
    electricCar.startEngine();
    
    Engine gasolineEngine = new GasolineEngine();
    Car gasolineCar = new Car(gasolineEngine);
    gasolineCar.startEngine();
  }
}

上面定义了一个 Engine 接口,其中start 方法用于启动引擎。ElectricEngine 类和 GasolineEngine 类分别实现了 Engine 接口,并分别负责执行电动引擎和汽油引擎的启动逻辑。Car 类表示汽车,其中包含一个引擎对象。通过 startEngine 方法,我们可以启动汽车的引擎,而不需要了解具体是电动引擎还是汽油引擎。在 Main 类中,我们创建了一个电动引擎对象,并用它来实例化一个电动车对象。然后,我们创建了一个汽油引擎对象,并用它来实例化一个汽油车对象。最后,我们分别启动了电动车和汽油车的引擎。通过将汽车类与引擎接口组合起来,我们实现了合成复用原则。汽车类通过引擎接口与具体的引擎实现进行交互,而不需要与具体的引擎类直接交互。

三、适用对象:面向对象编程

  • 两大编程思想
  1. 面向过程:首先分析出解决问题所需要的步骤,然后通过代码实现
  2. 面向对象:功能封装在功能内部,实现功能通过调用对象方法来实现
  • 面向对象编程的优势:
  1. 在面向对象程序开发思想中,每一个对象都是功能中心,具有明确的分功
  2. 面向对象编程具有灵活,代码可复用,容易维护和开发的优点,更适合多人合作的大型软件项目
  • 面想对象的3大特性
    封装,继承,多态

四、GoF23有什么?按目的三大类,按适用范围两大类,共23种

范围/目的创建型模式5种结构型模式7种行为型模式11种
类模式4种工厂方法模式(类)适配器模式解释器模式、模板方法模式
对象模式19抽象工厂模式
建造者模式
原型模式
单例模式
(对象)适配器模式
桥接模式
组合模式
装饰模式
外观模式
享元模式
代理模式
职责链模式
命令模式
迭代器模式
中介者模式
备忘录模式
观察者模式
状态模式
策略模式
访问者模式

5种创建型模式:用于创建对象,

单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。

具体展示
1. 单例模式、

目的:生成关于某个类全局唯一的对象,用于解决一个全局使用的类频繁地创建与销毁的问题。
分类:有懒汉式、饿汉式等。

//饿汉式或者静态内部类的方式
public class Singleton {
  private static final Singleton instance = new Singleton();

  private Singleton() {
    // 私有构造函数,防止外部实例化
  }

  public static Singleton getInstance() {
    return instance;
  }

  // 其他成员方法...
}

public class Main {
  public static void main(String[] args) {
    Singleton singleton = Singleton.getInstance();
    // 使用单例对象进行操作...
  }
}

上面Singleton 类有一个私有静态成员变量 instance,它在类加载时被初始化为一个唯一的实例。getInstance 方法是公共静态方法,直接返回已经初始化的 instance。在 Main 类的 main 方法中,通过调用 Singleton.getInstance() 来获取 Singleton 的实例,并将它赋值给 singleton 变量。然后,就可以使用 singleton 对象进行操作。无论何时调用 getInstance 方法,都会返回同一个实例,确保只有一个 Singleton 对象存在。

//基于双重检查锁定的懒汉式
public class Singleton {
  private static volatile Singleton instance;

  private Singleton() {
    // 私有构造函数,防止外部实例化
  }

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

  // 其他成员方法...
}

public class Main {
  public static void main(String[] args) {
    Singleton singleton = Singleton.getInstance();
    // 使用单例对象进行操作...
  }
}

上面Singleton 类有一个私有静态成员变量 instance,它被声明为 volatile 关键字修饰的变量,用于确保多线程环境下的可见性。getInstance 方法是公共静态方法,使用双重检查锁定来实现延迟初始化。首先检查 instance 是否为 null,如果是,则进入同步块。在同步块内部再次检查 instance 是否为 null,以确保只有一个线程创建实例。在实例创建完成后,在同步块外的线程也会直接返回已经初始化的 instance。在 Main 类的 main 方法中,我们通过调用 Singleton.getInstance() 来获取 Singleton 的实例,并将它赋值给 singleton 变量。然后,就可以使用 singleton 对象进行操作。无论何时调用 getInstance 方法,都会返回同一个实例,确保只有一个 Singleton 对象存在。需要注意的是,使用双重检查锁定需要考虑到多线程环境下的内存可见性问题,因此在 instance 前面加上 volatile 关键字进行修饰。

2.工厂模式

目的:借用了模板模式来创建产品,是一种非常重要用处很广的一种方法

    function creatCar (color, style) {//批量创建对象
      var obj = new Object()
      obj.color = color
      obj.style = style
      return obj
    }
    var Byd = creatCar('red', '比亚迪')
    var Car911 = creatCar('blue', '小蜜蜂')
  • 构造函数与工厂模式的区别
一、(显示来说)

1. 在构造函数中,没有显示的创建对象,在构造函数内部么有通过new关键字
2. 在构造函数中,直接将属性和方法赋值给了this对象,this指的就是当前的实例,也可以说是当前构造函数的作用域
3. 在构造函数中,没有return语句

二、构造函数创建对象内部的处理

1. 在构造函数内部,创建一个新对象,是隐式创建
2. 在构造函数内部,将构造函数的作用域赋给新对象
3. 在构造函数内部,执行构造函数中的代码,在实例化时,构造函数里面的代码是逐行执行的
4. 在构造函数内部,返回新对象
5. 构造函数存在内存浪费问题
//简单工厂模式
public interface Product {
  void doSomething();
}

public class ConcreteProduct implements Product {
  @Override
  public void doSomething() {
    // 具体产品的实现逻辑
  }
}

public class SimpleFactory {
  public static Product createProduct(String type) {
    if ("A".equals(type)) {
      return new ConcreteProduct();
    } else {
      throw new IllegalArgumentException("Invalid product type");
    }
  }
}

public class Main {
  public static void main(String[] args) {
    Product product = SimpleFactory.createProduct("A");
    product.doSomething();
    // 使用产品进行操作...
  }
}

上面,Product 接口定义了产品的抽象方法 doSomething()。ConcreteProduct 类实现了 Product 接口,并提供了具体产品的实现逻辑。SimpleFactory 类是简单工厂类,包含一个静态工厂方法 createProduct,根据传入的参数 type 创建不同类型的产品实例。在 Main 类的 main 方法中,通过调用SimpleFactory.createProduct(“A”) 来获取 ConcreteProduct 的实例,并将它赋值给 product 变量。然后就可以使用 product 对象进行操作。

3.抽象工厂模式、

目的:使用了工厂模式,组合模式等模式,面向抽象编程,将抽象零件组装成抽象产品,便于具体工厂的创建,提高了代码的组件化和复用性;

public interface AbstractFactory {
  ProductA createProductA();
  ProductB createProductB();
}

public class ConcreteFactory implements AbstractFactory {
  @Override
  public ProductA createProductA() {
    return new ConcreteProductA();
  }

  @Override
  public ProductB createProductB() {
    return new ConcreteProductB();
  }
}

public interface ProductA {
  void doSomething();
}

public interface ProductB {
  void doSomething();
}

public class ConcreteProductA implements ProductA {
  @Override
  public void doSomething() {
    // 具体产品A的实现逻辑
  }
}

public class ConcreteProductB implements ProductB {
  @Override
  public void doSomething() {
    // 具体产品B的实现逻辑
  }
}

public class Client {
  private AbstractFactory abstractFactory;

  public Client(AbstractFactory abstractFactory) {
    this.abstractFactory = abstractFactory;
  }

  public void doSomething() {
    ProductA productA = abstractFactory.createProductA();
    ProductB productB = abstractFactory.createProductB();
    // 使用产品A和产品B进行操作...
  }
}

public class Main {
  public static void main(String[] args) {
    AbstractFactory factory = new ConcreteFactory();
    Client client = new Client(factory);
    client.doSomething();
  }
}

上面定义了一个抽象工厂接口 AbstractFactory,其中声明了两个抽象方法 createProductA() 和 createProductB(),分别用于创建产品A和产品B。具体工厂类 ConcreteFactory 实现了抽象工厂接口,通过实现两个抽象方法分别创建具体的产品A和产品B的实例。产品A接口 ProductA 和产品B接口 ProductB 分别定义了各自的操作方法 doSomething()。具体产品类 ConcreteProductA 和 ConcreteProductB 实现了产品A和产品B的接口,并提供了各自的实现逻辑。客户端类 Client 通过抽象工厂接口持有具体工厂对象,并在执行 doSomething() 方法时,通过该工厂创建产品A和产品B的实例并进行操作。在 Main 类的 main 方法中,创建具体的抽象工厂对象 factory,并将其传递给客户端类 Client 的构造函数,然后调用 client.doSomething() 来使用产品A和产品B进行操作。

4.建造者模式、

目的:创建与使用分离,用一个新的类对已有的抽象接口进行整合和编程,从而构建出我们想要的东西

public class Product {
  private String partA;
  private String partB;

  public void setPartA(String partA) {
    this.partA = partA;
  }

  public void setPartB(String partB) {
    this.partB = partB;
  }

  public void show() {
    System.out.println("Part A: " + partA);
    System.out.println("Part B: " + partB);
  }
}

public interface Builder {
  void buildPartA();
  void buildPartB();
  Product getResult();
}

public class ConcreteBuilder implements Builder {
  private Product product = new Product();

  @Override
  public void buildPartA() {
    product.setPartA("Part A");
  }

  @Override
  public void buildPartB() {
    product.setPartB("Part B");
  }

  @Override
  public Product getResult() {
    return product;
  }
}

public class Director {
  public Product construct(Builder builder) {
    builder.buildPartA();
    builder.buildPartB();
    return builder.getResult();
  }
}

public class Main {
  public static void main(String[] args) {
    Builder builder = new ConcreteBuilder();
    Director director = new Director();
    Product product = director.construct(builder);
    product.show();
  }
}

上面Product 是待构建的复杂对象,它具有两个部分,即 PartA 和 PartB。该类提供了设置各部分的方法 setPartA() 和 setPartB(),以及展示结果的方法 show()。Builder 接口定义了构建产品的步骤,包括 buildPartA() 和 buildPartB() 方法,以及获取最终结果的方法 getResult()。ConcreteBuilder 实现了 Builder 接口,具体实现了构建产品各个部分的方法,并提供了获取最终结果的方法。Director 类负责控制构建过程,它接受一个具体的构建者对象,按照一定的顺序调用构建者的方法来构建产品,并返回最终的产品对象。在 Main 类的 main 方法中,创建一个具体的构建者对象 ConcreteBuilder,再实例化 Director 对象并调用其 construct() 方法,将构建者对象传递进去。最后通过获取产品对象并调用 show() 方法展示构建的结果。

5.原型模式 prototype

目的:clone/copy来提效。
其他方式对比:new一个新的、克隆一个副本。
常见:Cloneable接口、clone()方法函数。
结构:抽象原型类、具体原型类、访问类

  • 抽象原型类:规定了具体原型对象必须实现的接口
  • 具体原型类:实现抽象原型类的clone()方法,它是可被复制的对象
  • 访问类:使用具体原型类中的clone()方法来复制新的对象

通过UML来表达原型模式
在这里插入图片描述
在这里插入图片描述

分类:原型模式的拷贝分为浅拷贝和深拷贝。Deep copy and light copy

  • 基本数据类型
    string number boolean null undefined
  • 引入数据类型
    object (Array Object Function Map Set)
  • 深浅拷贝的实现
    浅拷贝只会拷贝引用数据数据类型的地址,当某个数据被修改后,也会影响到另一个拷贝的数据
    深拷贝会拷贝多层,对于每一级的数据都会拷贝
    在这里插入图片描述
    在这里插入图片描述

什么是原型?(以某个对象为原型进行拷贝)

1.每一个对象都有prototype(表示原型)属性,函数也是对象的一种,打印结果为原型对象
2.obj对象的原型对象Fn的原型对象的Prototype属性下有 proto (对象原型)属性,其实指向的就是prototype(原型对象)

1.公共方法写在原型对象
Star.prototype.sing = function(){console.log('唱歌')}
ldh.sing()//调用 唱歌
zxy.sing()//调用 唱歌
console.log(ldh.sing === zxy.sing)//true
2.公共属性写在构造函数

在这里插入图片描述

  • java代码表示
//1.通过类创建一个对象
//2.实现克隆:01、实现一个接口Cloneable 02、重写一个方法clone()
package comkuang prototypedemo01;
import java.util.Date;
//Video视频
public class Video implements Cloneable{
	private String name;//视频名称
	private Date createTime;//视频创建时间
	@Override
	protected Object clone() throws CloneNotSupportedException{
	return super.clone();
}

7种结构型模式:用于处理类和对象的组合

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

具体展示
1.适配器模式,

目的:它将不同的接口进行适配,从而便于版本的兼容性以及其他功能

// 目标接口
public interface Target {
  void request();
}

// 需要适配的类
public class Adaptee {
  public void specificRequest() {
    // 具体业务逻辑
  }
}

// 适配器类
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();
  }
}

上面有一个目标接口 Target,其中声明了一个抽象方法 request(),表示客户端需要调用的方法。Adaptee 是需要被适配的类,它已经存在并且有自己的一些方法,其中包括 specificRequest() 方法。
Adapter 类是适配器类,它实现了目标接口 Target。在适配器类中,我们通过组合方式持有了一个 Adaptee 对象,并在 request() 方法中调用了 Adaptee 的 specificRequest() 方法。
在客户端的 Client 类中,我们创建了一个 Adaptee 对象和一个 Adapter 对象,并将 Adaptee 对象传递给 Adapter 的构造函数。然后,我们可以通过 Target 接口来调用适配后的方法。

2. 桥接模式,

目的:将类的功能层次和实现层次分割开来,便于对应的扩展和使用。或者说将抽象部分与它的实现部分分离,使它们都可以独立变化。

  • 实例
    在这里插入图片描述
  • 参考http://t.csdn.cn/GPjeO
// 实现接口
public interface Implementor {
  void operationImpl();
}

// 具体实现类A
public class ConcreteImplementorA implements Implementor {
  @Override
  public void operationImpl() {
    // 实现具体的操作逻辑
  }
}

// 具体实现类B
public class ConcreteImplementorB implements Implementor {
  @Override
  public void operationImpl() {
    // 实现具体的操作逻辑
  }
}

// 抽象类
public abstract class Abstraction {
  protected Implementor implementor;

  public Abstraction(Implementor implementor) {
    this.implementor = implementor;
  }

  public abstract void operation();
}

// 扩展抽象类
public class RefinedAbstraction extends Abstraction {
  public RefinedAbstraction(Implementor implementor) {
    super(implementor);
  }

  @Override
  public void operation() {
    // 扩展的操作逻辑
    implementor.operationImpl();
    // 扩展的操作逻辑
  }
}

// 客户端代码
public class Client {
  public static void main(String[] args) {
    Implementor implementor = new ConcreteImplementorA();
    Abstraction abstraction = new RefinedAbstraction(implementor);
    abstraction.operation();
  }
}

上面有一个实现接口 Implementor,其中声明了一个抽象方法 operationImpl(),表示具体实现类需要实现的操作逻辑。ConcreteImplementorA 和 ConcreteImplementorB 是具体实现类,它们分别实现了 Implementor 接口的 operationImpl() 方法。Abstraction 是抽象类,其中包含一个对 Implementor 的引用。它定义了一个抽象方法 operation(),表示具体子类需要实现的操作逻辑。RefinedAbstraction 是扩展抽象类,它继承了 Abstraction 类并实现了其 operation() 方法。在该方法中,我们可以通过调用 implementor 对象的 operationImpl() 方法来实现具体的操作,并在其前后添加扩展的操作逻辑。在客户端的 Client 类中,我们创建了一个 ConcreteImplementorA 对象和一个 RefinedAbstraction 对象,并将 ConcreteImplementorA 对象传递给 RefinedAbstraction 的构造函数。然后调用 abstraction 对象的 operation() 方法,即可执行桥接模式的操作。

3. 装饰模式,

目的:和组合模式的结构类似,同样是递归结构,从而可以不断的装饰,增加新的功能

// 组件接口
public interface Component {
  void operation();
}

// 具体组件类
public class ConcreteComponent implements Component {
  @Override
  public void operation() {
    // 实现具体的操作逻辑
  }
}

// 抽象装饰器类
public abstract class Decorator implements Component {
  protected Component component;

  public Decorator(Component component) {
    this.component = component;
  }

  @Override
  public void operation() {
    component.operation();
  }
}

// 具体装饰器类A
public class ConcreteDecoratorA extends Decorator {
  public ConcreteDecoratorA(Component component) {
    super(component);
  }

  @Override
  public void operation() {
    super.operation();
    // 执行具体装饰逻辑A
  }
}

// 具体装饰器类B
public class ConcreteDecoratorB extends Decorator {
  public ConcreteDecoratorB(Component component) {
    super(component);
  }

  @Override
  public void operation() {
    super.operation();
    // 执行具体装饰逻辑B
  }
}

// 客户端代码
public class Client {
  public static void main(String[] args) {
    Component component = new ConcreteComponent();
    Component decoratedComponent = new ConcreteDecoratorA(new ConcreteDecoratorB(component));
    decoratedComponent.operation();
  }
}

上面有一个组件接口 Component,其中声明了一个抽象方法 operation(),表示需要被装饰的操作。ConcreteComponent 是具体组件类,它实现了 Component 接口的 operation() 方法,定义了自己的具体操作逻辑。Decorator 是抽象装饰器类,它实现了 Component 接口,并持有一个 Component 对象。在 Decorator 类中,我们通过调用 component 对象的 operation() 方法来执行被装饰的操作。ConcreteDecoratorA 和 ConcreteDecoratorB 是具体装饰器类,它们继承了Decorator 类并实现了其 operation() 方法。在这两个装饰器类中,我们先调用父类的 operation() 方法以执行被装饰的操作,然后再添加额外的具体装饰逻辑。在客户端的 Client 类中,我们创建了一个 ConcreteComponent 对象,并通过多层装饰器的嵌套,依次对组件进行装饰,形成一个装饰器链条。最终,我们调用 decoratedComponent 对象的 operation() 方法,即可执行整个装饰器链条上的所有装饰逻辑。

4. 组合模式,

目的:保证了同根同源,通过委托添加自己构成递归,树形结构,将具有树形特点的对象组合起来;

import java.util.ArrayList;
import java.util.List;

// 组件接口
public interface Component {
  void operation();
}

// 叶子组件类
public class Leaf implements Component {
  @Override
  public void operation() {
    // 实现具体的操作逻辑
  }
}

// 容器组件类
public class Composite implements Component {
  private List<Component> components = new ArrayList<>();

  public void addComponent(Component component) {
    components.add(component);
  }

  public void removeComponent(Component component) {
    components.remove(component);
  }

  @Override
  public void operation() {
    for (Component component : components) {
      component.operation();
    }
  }
}

// 客户端代码
public class Client {
  public static void main(String[] args) {
    Component leaf1 = new Leaf();
    Component leaf2 = new Leaf();
    Component composite = new Composite();

    composite.addComponent(leaf1);
    composite.addComponent(leaf2);

    composite.operation();
  }
}

上面我们有一个组件接口 Component,其中声明了一个抽象方法 operation(),表示能够进行的操作。Leaf 是叶子组件类,它实现了 Component 接口的 operation() 方法,定义了自己的具体操作逻辑。Composite 是容器组件类,它实现了 Component 接口,并持有一个 components 集合用于存储子组件。在 Composite 类中,我们可以添加和移除子组件,并且在调用 operation() 方法时会遍历调用其中所有子组件的 operation() 方法。在客户端的 Client 类中,我们创建了两个叶子组件对象 leaf1 和 leaf2,以及一个容器组件对象 composite。然后,我们通过调用 composite 对象的 addComponent() 方法将叶子组件添加到容器中。最后调用 composite 对象的 operation() 方法,即可递归地执行容器及其子组件的操作。

5. 外观模式,

目的:通过整合各个类之间的调用关系,组建成了统一的接口(API),便于外部类的调用;

// 子系统类A
public class SubSystemA {
  public void operationA() {
    // 实现具体的操作逻辑
  }
}

// 子系统类B
public class SubSystemB {
  public void operationB() {
    // 实现具体的操作逻辑
  }
}

// 外观类
public class Facade {
  private SubSystemA subsystemA;
  private SubSystemB subsystemB;

  public Facade() {
    subsystemA = new SubSystemA();
    subsystemB = new SubSystemB();
  }

  public void operation() {
    subsystemA.operationA();
    subsystemB.operationB();
  }
}

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

上面我们有两个子系统类 SubSystemA 和 SubSystemB,它们分别实现了具体的操作逻辑。Facade 是外观类,它知道哪些子系统类负责处理客户端的请求,并将这些请求转发给相应的子系统对象进行处理。在 Facade 类中,我们持有 SubSystemA 和 SubSystemB 的实例,并定义了一个名为 operation() 的方法,该方法调用了子系统类的具体操作方法。在客户端的 Client 类中,我们创建了一个外观对象 facade,然后通过调用外观对象的 operation() 方法来间接地调用相应子系统的操作方法。通过外观模式,客户端可以通过简单地调用外观类提供的方法来完成复杂的操作,而无需直接与子系统类交互。外观模式将子系统的复杂性封装起来,隐藏了内部的具体实现细节,使得客户端更加简单和方便地使用子系统功能。

6. 享元模式,

目的:轻量级对象,通过共用不变对象来实现;通过共享对象来减少内存使用和提高性能
主要角色:抽象享元角色、具体享元角色、享元工厂(FlyweightFactory)角色、非享元角色

  • 例子:围棋只有黑白两色,所以棋子颜色就是棋子的内蕴状态;而各个棋子之间的差别就是位置的不同,落子时颜色固定,位置是变化。则方位坐标,也就是棋子的外蕴状态,即非享元角色;抽象享元角色是棋子;具体享元角色是白棋(内蕴状态)和黑棋(内蕴状态);

  • 类图(虚线表注释)
    在这里插入图片描述

  • 参考 http://t.csdn.cn/TqTry

import java.util.HashMap;
import java.util.Map;

// 享元接口
public interface Flyweight {
  void operation();
}

// 具体享元类
public class ConcreteFlyweight implements Flyweight {
  private String intrinsicState;

  public ConcreteFlyweight(String intrinsicState) {
    this.intrinsicState = intrinsicState;
  }

  @Override
  public void operation() {
    // 实现具体的操作逻辑
  }
}

// 享元工厂类
public class FlyweightFactory {
  private Map<String, Flyweight> flyweights = new HashMap<>();

  public Flyweight getFlyweight(String key) {
    if (flyweights.containsKey(key)) {
      return flyweights.get(key);
    } else {
      Flyweight flyweight = new ConcreteFlyweight(key);
      flyweights.put(key, flyweight);
      return flyweight;
    }
  }
}

// 客户端代码
public class Client {
  public static void main(String[] args) {
    FlyweightFactory factory = new FlyweightFactory();

    Flyweight flyweight1 = factory.getFlyweight("key1");
    flyweight1.operation();

    Flyweight flyweight2 = factory.getFlyweight("key2");
    flyweight2.operation();
  }
}

上面有一个享元接口 Flyweight,其中声明了一个抽象方法 operation(),表示能够进行的操作。
ConcreteFlyweight 是具体享元类,实现了 Flyweight 接口,并持有一个内部状态 intrinsicState,用于存储享元对象的内部状态。在 ConcreteFlyweight 类中,我们实现了 operation() 方法,定义了具体的操作逻辑。FlyweightFactory 是享元工厂类,它负责创建和管理享元对象。在 FlyweightFactory 类中,我们使用一个 flyweights Map 来缓存已经创建的享元对象。在 getFlyweight() 方法中,我们通过传入特定的键值 key 来获取对应的享元对象。如果该享元对象已经存在于缓存中,则直接返回;否则,我们创建一个新的具体享元对象,并将其加入到缓存中再返回。
在客户端的 Client 类中,我们首先创建一个享元工厂对象 factory。然后,通过调用 factory 对象的 getFlyweight() 方法并传入不同的 key 值来获取具体的享元对象。最后,我们可以调用所获取的享元对象的 operation() 方法来进行具体的操作。享元模式的核心思想是共享对象以减少内存占用,当多个对象拥有相同或相似的内部状态时,可以共享同一个享元对象,并且通过外部状态的变化来影响和区分享元对象的行为。

7. 代理模式

目的:懒加载真正的服务器,加快访问速度,代理是帮助服务器代理的;

// 主题接口
public interface Subject {
  void request();
}

// 真实主题类
public class RealSubject implements Subject {
  @Override
  public void request() {
    // 实现具体的请求逻辑
  }
}

// 代理类
public class Proxy implements Subject {
  private RealSubject realSubject;

  public Proxy() {
    realSubject = new RealSubject();
  }

  @Override
  public void request() {
    // 在调用真实主题对象前后可以添加额外的逻辑
    // ...
    realSubject.request();
    // ...
  }
}

// 客户端代码
public class Client {
  public static void main(String[] args) {
    Subject subject = new Proxy();
    subject.request();
  }
}

上面有一个主题接口 Subject,其中声明了一个抽象方法 request(),表示需要进行的请求。
RealSubject 是真实主题类,实现了 Subject 接口,并在 request() 方法中定义了具体的请求逻辑。
Proxy 是代理类,它也实现了 Subject 接口,并持有一个真实主题对象 realSubject 的引用。在 Proxy 类中,我们通过在 request() 方法中添加额外的逻辑(例如在调用真实主题对象之前或之后执行某些操作),从而对真实主题对象的请求进行控制和管理。在客户端的 Client 类中,我们创建了一个代理对象 subject,并调用其 request() 方法来发起请求。由于代理类实现了主题接口,因此客户端可以通过代理对象来操作和管理真实主题对象。代理模式的核心思想是在不改变原始对象的情况下,引入一个代理对象来控制对原始对象的访问。代理模式可以提供额外的功能,例如权限控制、延迟加载、缓存等,同时也可以在不直接访问敏感对象时进行保护。

11种行为型模式:用于描述对类和对象怎样交互和怎样分配职责

模板方法模式,命令模式,迭代器模式,观察者模式,中介者模式,备忘录模式,解释器模式,状态模式,策略模式,职责链模式,访问者模式。

具体展示
1. 模板方法模式,

目的:使用模板面向抽象编程,便于新的子类的实现和管理
适用范围:一次性实线算法中通用的作为不变部分,并将可变的行为留给子类
构成:模板类 + 模板子类(继承模板类)
作用:复用、扩展

// 抽象模板类
public abstract class AbstractClass {
  public void templateMethod() {
    // 公共逻辑1
    primitiveOperation1();
    // 公共逻辑2
    primitiveOperation2();
    // 公共逻辑3
    primitiveOperation3();
  }

  protected abstract void primitiveOperation1();
  protected abstract void primitiveOperation2();
  protected abstract void primitiveOperation3();
}

// 具体模板类
public class ConcreteClass extends AbstractClass {
  @Override
  protected void primitiveOperation1() {
    // 实现具体的操作1
  }

  @Override
  protected void primitiveOperation2() {
    // 实现具体的操作2
  }

  @Override
  protected void primitiveOperation3() {
    // 实现具体的操作3
  }
}

// 客户端代码
public class Client {
  public static void main(String[] args) {
    AbstractClass abstractClass = new ConcreteClass();
    abstractClass.templateMethod();
  }
}

上面我们有一个抽象模板类 AbstractClass,其中定义了一个模板方法 templateMethod(),表示一个算法或操作的骨架。在模板方法内部,包含了三个公共逻辑(公共步骤),分别是 primitiveOperation1()、primitiveOperation2() 和 primitiveOperation3()。ConcreteClass 是具体模板类,继承自 AbstractClass 并实现了其抽象方法。在具体模板类中,我们根据具体的需求实现了每个抽象方法,用于完成算法或操作的具体步骤。在客户端的 Client 类中,我们创建了一个具体模板对象 abstractClass,并调用其 templateMethod() 方法来执行模板算法。模板方法内部会按照定义的顺序调用公共逻辑和具体操作,从而完成整体的算法流程。模板方法模式的核心思想是将算法的通用结构定义在一个模板方法中,由子类提供具体的实现细节。通过使用模板方法模式,可以避免代码重复,提高代码的复用性,并且能够灵活地扩展和定制具体的实现。

2. 命令模式

目的:将命令当做类,通过保存一些列命令,从而能够随时执行这些命令,需要清除命令的本质就是一些操作和数据;

// 命令接口
public interface Command {
  void execute();
}

// 具体命令类
public class ConcreteCommand implements Command {
  private Receiver receiver;

  public ConcreteCommand(Receiver receiver) {
    this.receiver = receiver;
  }

  @Override
  public void execute() {
    receiver.action();
  }
}

// 接收者类
public class Receiver {
  public void action() {
    // 执行具体操作
  }
}

// 请求者类
public class Invoker {
  private Command command;

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

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

// 客户端代码
public class Client {
  public static void main(String[] args) {
    Receiver receiver = new Receiver();
    Command command = new ConcreteCommand(receiver);
    Invoker invoker = new Invoker();
    invoker.setCommand(command);
    invoker.executeCommand();
  }
}

上面我们有一个命令接口 Command,其中声明了一个抽象方法 execute(),用于执行具体的命令。ConcreteCommand 是具体命令类,实现了 Command 接口,并持有一个接收者对象 receiver 的引用。在 execute() 方法中,调用接收者对象的 action() 方法,以执行具体的操作。
Receiver 是接收者类,定义了具体的操作逻辑,在 action() 方法中完成具体的操作。
Invoker 是请求者类,持有一个命令对象的引用,通过 setCommand() 方法来设置具体的命令。在 executeCommand() 方法中,调用命令对象的 execute() 方法,从而执行具体的命令。
在客户端的 Client 类中,我们创建了一个接收者对象 receiver、一个具体命令对象 command(传入接收者对象作为参数),以及一个请求者对象 invoker。然后,将具体命令对象设置到请求者对象中,并调用请求者对象的 executeCommand() 方法来触发具体命令的执行。
命令模式的核心思想是将请求封装成一个对象,从而使得请求者和接收者解耦。通过使用命令模式,可以实现对请求进行参数化、队列化、撤销和重做等操作。

3. 迭代器模式,

目的:将类中数据结构的遍历和类的功能实现分离出来,本质上使用了工厂模式

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

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

// 具体迭代器类
public class ConcreteIterator implements Iterator {
  private Object[] items;
  private int position = 0;

  public ConcreteIterator(Object[] items) {
    this.items = items;
  }

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

  @Override
  public Object next() {
    Object item = items[position];
    position++;
    return item;
  }
}

// 具体集合类
public class ConcreteAggregate implements Aggregate {
  private Object[] items;

  public ConcreteAggregate(Object[] items) {
    this.items = items;
  }

  @Override
  public Iterator createIterator() {
    return new ConcreteIterator(items);
  }
}

// 客户端代码
public class Client {
  public static void main(String[] args) {
    Object[] items = { "Item 1", "Item 2", "Item 3" };
    Aggregate aggregate = new ConcreteAggregate(items);
    Iterator iterator = aggregate.createIterator();

    while (iterator.hasNext()) {
      Object item = iterator.next();
      System.out.println(item);
    }
  }
}

我们有一个迭代器接口 Iterator,其中定义了两个方法 hasNext() 和 next()。hasNext() 方法用于判断是否还有下一个元素,next() 方法用于返回下一个元素。
Aggregate 是集合接口,定义了一个方法 createIterator(),用于创建迭代器对象。
ConcreteIterator 是具体迭代器类,实现了迭代器接口。在具体迭代器中,使用一个数组 items 来存储元素,并通过 position 变量来追踪当前的位置。hasNext() 方法检查当前位置是否还有元素,next() 方法返回当前位置的元素,并将位置向后移动一位。
ConcreteAggregate 是具体集合类,实现了集合接口。在具体集合类中,持有一个数组 items,并实现了 createIterator() 方法,返回一个具体迭代器对象。
在客户端的 Client 类中,我们创建了一个存储对象数组 items,然后使用具体集合类 ConcreteAggregate 创建了一个集合对象 aggregate。通过调用集合对象的 createIterator() 方法得到一个具体迭代器对象 iterator。
最后,我们使用迭代器对象循环遍历集合中的元素,并打印出每个元素的值。
迭代器模式的核心思想是提供一种统一的方法访问一个容器对象中的各个元素,而无需暴露内部的表示方式。通过使用迭代器模式,可以遍历集合对象而无需了解其内部结构。

4. 观察者模式,

目的:通过互相委托从而能够在被观察的类发生改变的时候得到相应的改变的信息并且处理;

import java.util.ArrayList;
import java.util.List;

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

// 具体主题类
public class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private int state;

    @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(state);
        }
    }

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

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

// 具体观察者类
public class ConcreteObserver implements Observer {
    @Override
    public void update(int state) {
        System.out.println("State updated: " + state);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        ConcreteObserver observer1 = new ConcreteObserver();
        ConcreteObserver observer2 = new ConcreteObserver();

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

        subject.setState(123);
    }
}

我们有一个主题接口 Subject,其中定义了注册观察者、移除观察者和通知观察者的方法。
ConcreteSubject 是具体主题类,实现了主题接口。在具体主题类中,使用一个列表 observers 来存储观察者对象,并使用一个整型变量 state 来表示状态。在注册观察者时,将观察者对象添加到列表中;在移除观察者时,从列表中移除观察者;在通知观察者时,遍历观察者列表,调用每个观察者的 update() 方法。
Observer 是观察者接口,定义了一个更新方法 update(),该方法在主题状态发生变化时被调用。
ConcreteObserver 是具体观察者类,实现了观察者接口。在具体观察者类中,实现了 update() 方法,在该方法中处理主题状态变化的通知。
在客户端的 Client 类中,我们创建了一个具体主题对象 subject,以及两个具体观察者对象 observer1 和 observer2。然后,通过调用主题对象的 registerObserver() 方法将观察者对象注册到主题中。最后,使用主题对象的 setState() 方法更新主题的状态,从而触发观察者的更新。
观察者模式的核心思想是定义了一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,它会通知所有观察者对象,使它们能够自动更新。

5. 中介者模式,
import java.util.ArrayList;
import java.util.List;

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

// 抽象同事类
public abstract class Colleague {
    protected Mediator mediator;

    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }

    public abstract void receiveMessage(String message);
    public abstract void sendMessage(String message);
}

// 具体同事类
public class ConcreteColleague1 extends Colleague {
    public ConcreteColleague1(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void receiveMessage(String message) {
        System.out.println("ConcreteColleague1 Received: " + message);
    }

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

// 具体同事类
public class ConcreteColleague2 extends Colleague {
    public ConcreteColleague2(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void receiveMessage(String message) {
        System.out.println("ConcreteColleague2 Received: " + message);
    }

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

// 具体中介者类
public class ConcreteMediator implements Mediator {
    private List<Colleague> colleagues = new ArrayList<>();

    public void addColleague(Colleague colleague) {
        colleagues.add(colleague);
    }

    @Override
    public void sendMessage(String message, Colleague colleague) {
        for (Colleague c : colleagues) {
            if (c != colleague) {
                c.receiveMessage(message);
            }
        }
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        ConcreteMediator mediator = new ConcreteMediator();
        ConcreteColleague1 colleague1 = new ConcreteColleague1(mediator);
        ConcreteColleague2 colleague2 = new ConcreteColleague2(mediator);

        mediator.addColleague(colleague1);
        mediator.addColleague(colleague2);

        colleague1.sendMessage("Hello, colleague2!");
        colleague2.sendMessage("Hi, colleague1!");
    }
}

我们有一个中介者接口 Mediator,其中定义了发送消息的方法。
Colleague 是抽象同事类,持有一个中介者对象。在抽象同事类中,定义了接收消息和发送消息的抽象方法。
ConcreteColleague1 和 ConcreteColleague2 是具体同事类,继承自抽象同事类。在具体同事类中,实现了接收消息和发送消息的方法。在发送消息的方法中,调用中介者的 sendMessage() 方法。
ConcreteMediator 是具体中介者类,实现了中介者接口。在具体中介者类中,使用一个列表 colleagues 来存储同事对象。在添加同事对象时,将同事对象添加到列表中。在发送消息时,遍历同事列表,并调用每个同事对象的 receiveMessage() 方法,同时排除发送消息的同事对象本身。
在客户端的 Client 类中,我们创建了一个具体中介者对象 mediator,以及两个具体同事对象 colleague1 和 colleague2。然后,将同事对象添加到中介者的同事列表中。最后,通过调用同事对象的 sendMessage() 方法发送消息。
中介者模式的核心思想是将多个对象之间的交互行为封装在一个中介者对象中,从而使对象之间松耦合,并且可以独立地改变它们之间的交互行为。中介者模式实现了 “集中控制、分散协作” 的目标。

6. 备忘录模式,

目的:通过在某一时刻的状态保存下来,便于恢复,在游戏中使用的比较多;

import java.util.ArrayList;
import java.util.List;

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

// 抽象同事类
public abstract class Colleague {
    protected Mediator mediator;

    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }

    public abstract void receiveMessage(String message);
    public abstract void sendMessage(String message);
}

// 具体同事类
public class ConcreteColleague1 extends Colleague {
    public ConcreteColleague1(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void receiveMessage(String message) {
        System.out.println("ConcreteColleague1 Received: " + message);
    }

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

// 具体同事类
public class ConcreteColleague2 extends Colleague {
    public ConcreteColleague2(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void receiveMessage(String message) {
        System.out.println("ConcreteColleague2 Received: " + message);
    }

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

// 具体中介者类
public class ConcreteMediator implements Mediator {
    private List<Colleague> colleagues = new ArrayList<>();

    public void addColleague(Colleague colleague) {
        colleagues.add(colleague);
    }

    @Override
    public void sendMessage(String message, Colleague colleague) {
        for (Colleague c : colleagues) {
            if (c != colleague) {
                c.receiveMessage(message);
            }
        }
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        ConcreteMediator mediator = new ConcreteMediator();
        ConcreteColleague1 colleague1 = new ConcreteColleague1(mediator);
        ConcreteColleague2 colleague2 = new ConcreteColleague2(mediator);

        mediator.addColleague(colleague1);
        mediator.addColleague(colleague2);

        colleague1.sendMessage("Hello, colleague2!");
        colleague2.sendMessage("Hi, colleague1!");
    }
}

我们有一个主题接口 Subject,其中定义了注册观察者、移除观察者和通知观察者的方法。
ConcreteSubject 是具体主题类,实现了主题接口。在具体主题类中,使用一个列表 observers 来存储观察者对象,并使用一个整型变量 state 来表示状态。在注册观察者时,将观察者对象添加到列表中;在移除观察者时,从列表中移除观察者;在通知观察者时,遍历观察者列表,调用每个观察者的 update() 方法。
Observer 是观察者接口,定义了一个更新方法 update(),该方法在主题状态发生变化时被调用。
ConcreteObserver 是具体观察者类,实现了观察者接口。在具体观察者类中,实现了 update() 方法,在该方法中处理主题状态变化的通知。
在客户端的 Client 类中,我们创建了一个具体主题对象 subject,以及两个具体观察者对象 observer1 和 observer2。然后,通过调用主题对象的 registerObserver() 方法将观察者对象注册到主题中。最后,使用主题对象的 setState() 方法更新主题的状态,从而触发观察者的更新。
观察者模式的核心思想是定义了一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,它会通知所有观察者对象,使它们能够自动更新。

7. 解释器模式,

目的:利用编程原理的方法,来更高层次的封装代码,将自己开发的java代码当做编译系统,从而不用改变java代码只修改更高语言层次的代码就能实现不同的功能。

import java.util.Stack;

// 抽象表达式接口
interface Expression {
    int interpret();
}

// 终结符表达式类
class NumberExpression implements Expression {
    private int number;

    public NumberExpression(int number) {
        this.number = number;
    }

    public int interpret() {
        return number;
    }
}

// 非终结符表达式类
class AddExpression implements Expression {
    private Expression leftExpression;
    private Expression rightExpression;

    public AddExpression(Expression leftExpression, Expression rightExpression) {
        this.leftExpression = leftExpression;
        this.rightExpression = rightExpression;
    }

    public int interpret() {
        return leftExpression.interpret() + rightExpression.interpret();
    }
}

// 上下文类
class Context {
    private Stack<Expression> expressionStack;

    public Context() {
        expressionStack = new Stack<>();
    }

    public void pushExpression(Expression expression) {
        expressionStack.push(expression);
    }

    public Expression popExpression() {
        return expressionStack.pop();
    }

    public Expression peekExpression() {
        return expressionStack.peek();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 构建解析树:4 + (3 + 2)
        Context context = new Context();
        context.pushExpression(new NumberExpression(4));
        context.pushExpression(new NumberExpression(3));
        context.pushExpression(new NumberExpression(2));
        Expression rightExpression = context.popExpression();
        Expression leftExpression = context.popExpression();
        context.pushExpression(new AddExpression(leftExpression, rightExpression));

        // 计算解析结果
        Expression expression = context.popExpression();
        int result = expression.interpret();
        System.out.println("Result: " + result);
    }
}

我们定义了一个简单的表达式语言,包括数字表达式和加法表达式。
Expression 是抽象表达式接口,定义了 interpret() 方法用于解释表达式。
NumberExpression 是终结符表达式类,表示一个数字表达式。
AddExpression 是非终结符表达式类,表示一个加法表达式,包含左子表达式和右子表达式。
Context 是上下文类,用于存储和管理表达式的解析树。
在客户端的 Client 类中,我们构建一个解析树:4 + (3 + 2)。首先,将数字表达式 4、3、2 入栈,然后将右子表达式和左子表达式出栈并构建一个加法表达式入栈。最后,获取整个解析树的根节点,即最终的表达式,计算解析结果为 9。

8. 状态模式,

目的:将状态当做类,从而职责分明,解除了很多繁琐的if和else这些分支逻辑,便于扩展;

// 状态接口
interface State {
    void switchOn();
    void switchOff();
}

// 具体状态类:开启状态
class OnState implements State {
    public void switchOn() {
        System.out.println("The light is already on.");
    }

    public void switchOff() {
        System.out.println("Switching off the light.");
    }
}

// 具体状态类:关闭状态
class OffState implements State {
    public void switchOn() {
        System.out.println("Switching on the light.");
    }

    public void switchOff() {
        System.out.println("The light is already off.");
    }
}

// 环境类
class Light {
    private State currentState;

    public Light() {
        currentState = new OffState();  // 初始状态为关闭状态
    }

    public void setState(State state) {
        currentState = state;
    }

    public void switchOn() {
        currentState.switchOn();
        setState(new OnState());
    }

    public void switchOff() {
        currentState.switchOff();
        setState(new OffState());
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Light light = new Light();

        light.switchOn();  // 进行状态切换
        light.switchOff();
        light.switchOff();  // 再次调用关闭操作,不会有实际效果
        light.switchOn();
    }
}

我们有两个具体状态类 OnState 和 OffState,它们实现了共同的状态接口 State,并根据不同的状态执行相应的操作。
Light 是环境类,其中包含 currentState 属性表示当前的状态。通过调用方法 switchOn() 和 switchOff(),它会委托给当前状态对象来处理具体的操作,并根据需要切换到新的状态。
在客户端的 Client 类中,我们创建一个灯对象 light。首先,调用 switchOn() 方法将灯开启,此时状态切换为开启状态,并打印相关信息。然后,调用 switchOff() 方法将灯关闭,此时状态切换为关闭状态,并打印相关信息。再次调用 switchOff() 方法,由于灯已经处于关闭状态,所以不会有实际效果。最后,再次调用 switchOn() 方法,将灯重新开启。

9. 策略模式,

目的:可以整体的替换策略,使用也很广泛

// 抽象策略接口
interface DiscountStrategy {
    double applyDiscount(double totalPrice);
}

// 具体策略类:无折扣
class NoDiscountStrategy implements DiscountStrategy {
    public double applyDiscount(double totalPrice) {
        return totalPrice;
    }
}

// 具体策略类:打九折
class TenPercentOffStrategy implements DiscountStrategy {
    public double applyDiscount(double totalPrice) {
        return totalPrice * 0.9;
    }
}

// 具体策略类:满200减50
class FiftyOffOn200Strategy implements DiscountStrategy {
    public double applyDiscount(double totalPrice) {
        if (totalPrice >= 200) {
            return totalPrice - 50;
        } else {
            return totalPrice;
        }
    }
}

// 上下文类
class ShoppingCart {
    private DiscountStrategy discountStrategy;

    public void setDiscountStrategy(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    public double calculateTotalPrice(double totalPrice) {
        return discountStrategy.applyDiscount(totalPrice);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        cart.setDiscountStrategy(new NoDiscountStrategy());  // 无折扣策略
        double totalPrice = 100.0;
        double discountedPrice = cart.calculateTotalPrice(totalPrice);
        System.out.println("Total price: " + discountedPrice);

        cart.setDiscountStrategy(new TenPercentOffStrategy());  // 打九折策略
        totalPrice = 200.0;
        discountedPrice = cart.calculateTotalPrice(totalPrice);
        System.out.println("Total price: " + discountedPrice);

        cart.setDiscountStrategy(new FiftyOffOn200Strategy());  // 满200减50策略
        totalPrice = 250.0;
        discountedPrice = cart.calculateTotalPrice(totalPrice);
        System.out.println("Total price: " + discountedPrice);
    }
}

我们有三个具体的策略类 NoDiscountStrategy、TenPercentOffStrategy 和 FiftyOffOn200Strategy,它们实现了共同的策略接口 DiscountStrategy,并分别对应不同的打折方式。
ShoppingCart 是上下文类,它包含一个 discountStrategy 属性表示当前的打折策略。通过调用 calculateTotalPrice() 方法,并传入总价,它会委托给当前策略对象来应用相应的打折计算。
在客户端的 Client 类中,我们创建一个购物车对象 cart。首先,将策略设置为无折扣策略,并计算总价为 100.0 的折扣价格,然后打印结果。接着,将策略设置为打九折策略,并计算总价为 200.0 的折扣价格,再次打印结果。最后,将策略设置为满200减50策略,并计算总价为 250.0 的折扣价格,再次打印结果。

10. 职责链模式,

目的:推卸责任,根据问题的大小来考虑自己释放处理,本质是链表,便于职责分明;

// 抽象处理器
abstract class LeaveHandler {
    protected LeaveHandler nextHandler;

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

    public abstract void handleLeave(int days);
}

// 具体处理器:组长
class TeamLeader extends LeaveHandler {
    public void handleLeave(int days) {
        if (days <= 2) {
            System.out.println("Team Leader: Approve leave for " + days + " days.");
        } else if (nextHandler != null) {
            nextHandler.handleLeave(days);
        }
    }
}

// 具体处理器:经理
class Manager extends LeaveHandler {
    public void handleLeave(int days) {
        if (days <= 5) {
            System.out.println("Manager: Approve leave for " + days + " days.");
        } else if (nextHandler != null) {
            nextHandler.handleLeave(days);
        }
    }
}

// 具体处理器:总经理
class CEO extends LeaveHandler {
    public void handleLeave(int days) {
        if (days <= 10) {
            System.out.println("CEO: Approve leave for " + days + " days.");
        } else {
            System.out.println("CEO: Leave request denied.");
        }
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        LeaveHandler teamLeader = new TeamLeader();
        LeaveHandler manager = new Manager();
        LeaveHandler ceo = new CEO();

        teamLeader.setNextHandler(manager);
        manager.setNextHandler(ceo);

        teamLeader.handleLeave(3);  // 组长审批,请假3天
        System.out.println("---");
        teamLeader.handleLeave(6);  // 组长审批,请假6天
        System.out.println("---");
        teamLeader.handleLeave(11);  // 组长审批,请假11天
    }
}

我们有三个具体的处理器类 TeamLeader、Manager 和 CEO,它们都继承自抽象处理器类 LeaveHandler,并实现了处理请假的具体逻辑。
每个具体处理器类都有一个 handleLeave() 方法来处理请假申请,并根据请假天数判断是否可以审批该请假申请。如果自身无法处理该请假申请,则通过调用 nextHandler.handleLeave(days) 将请求传递给下一个处理器。
在客户端的 Client 类中,我们创建了一个组长、一个经理和一个总经理,并将它们按照处理顺序连接起来。首先,调用组长的 handleLeave() 方法并传入请假天数为 3,组长会根据条件判断是否能够审批该请假申请,并输出结果。接着,再次调用组长的 handleLeave() 方法并传入请假天数为 6,这次请假天数超过了组长的审批范围,于是请求会自动传递给下一个处理器,即经理。最后,再次调用组长的 handleLeave() 方法并传入请假天数为 11,这次请假天数超过了总经理的审批范围,于是总经理直接拒绝了该请假申请。

11. 访问者模式

目的:通过在类外访问类中的数据结构从而得到想要的结果,便于程序的可扩展性和组件化;

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

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

    public String operationA() {
        return "ConcreteElementA operation called.";
    }
}

// 具体元素类B
class ConcreteElementB implements Element {
    public void accept(Visitor visitor) {
        visitor.visitElementB(this);
    }

    public String operationB() {
        return "ConcreteElementB operation called.";
    }
}

// 抽象访问者接口
interface Visitor {
    void visitElementA(ConcreteElementA elementA);
    void visitElementB(ConcreteElementB elementB);
}

// 具体访问者类
class ConcreteVisitor implements Visitor {
    public void visitElementA(ConcreteElementA elementA) {
        System.out.println("Visitor is visiting " + elementA.operationA());
    }

    public void visitElementB(ConcreteElementB elementB) {
        System.out.println("Visitor is visiting " + elementB.operationB());
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Element elementA = new ConcreteElementA();
        Element elementB = new ConcreteElementB();

        Visitor visitor = new ConcreteVisitor();

        elementA.accept(visitor);
        elementB.accept(visitor);
    }
}

我们有两个具体的元素类 ConcreteElementA 和 ConcreteElementB,它们都实现了抽象元素接口 Element。每个具体元素类都有一个 accept() 方法,接收一个访问者对象作为参数并调用该访问者的具体访问方法。
我们还定义了一个抽象访问者接口 Visitor,其中声明了访问每个具体元素的方法。具体访问者类 ConcreteVisitor 实现了抽象访问者接口,并实现了访问具体元素的具体操作。
在客户端的 Client 类中,我们创建了一个具体元素A和一个具体元素B,并创建了一个具体访问者对象。然后,分别调用每个元素的 accept() 方法,并将具体访问者对象传递进去。元素会根据具体访问者的类型调用相应的访问方法,从而完成访问操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值