设计模式 -java篇

365 阅读26分钟

Java设计模式

  • 设计模式简介

  • Java中使用设计模式的重要性

  • java中使用设计模式的目的和优点

  • 设计原则

    • 单一职责原则 (SRP)
    • 开放封闭原则 (OCP)
    • 里氏替换原则 (LSP)
    • 接口隔离原则 (ISP)
    • 依赖倒置原则 (DIP)
    • 迪米特法则 (LoD)
    • 合成复用原则 (CRP)
  • 设计模式类型

    • 创建型模式

      • 单例模式
      • 工厂方法模式
      • 抽象工厂模式
      • 建造者模式
      • 原型模式
    • 结构型模式

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

      • 职责链模式
      • 命令模式
      • 解释器模式
      • 迭代器模式
      • 中介者模式
      • 备忘录模式
      • 观察者模式
      • 状态模式
      • 策略模式
      • 模板方法模式
      • 访问者模式
  • 使用设计模式的最佳实践

  • 相关推荐



设计模式简介

设计模式是一种被广泛应用于软件开发中的解决特定问题的方案。它们是经验丰富的程序员和软件设计师发现和总结的一些最佳实践,可以帮助开发人员更有效地解决各种问题。使用设计模式,可以提高代码的可读性、可维护性和可扩展性,同时还可以降低代码的复杂度和错误率。

设计模式的目的是提高代码的质量和可重用性。通过使用设计模式,开发人员可以在设计和实现软件时遵循一些经过验证的最佳实践,从而减少代码的错误和复杂性,提高代码的可读性和可维护性,同时也可以提高代码的复用性和扩展性。

在软件设计中,高内聚和低耦合是两个非常重要的概念。高内聚是指模块内的元素相互关联度高,共同完成一个特定的任务。这意味着高内聚的模块设计更容易理解和维护,因为它们处理的问题更具体和清晰。实现高内聚的模块设计有助于减少代码中的混乱和错误,同时也可以提高代码的可读性和可维护性。例如,一个高内聚的模块可以更容易地测试和调试,因为它的功能更加明确,不需要涉及其他功能。

相反,低耦合是指模块之间的关系简单,尽可能少地相互影响。这意味着低耦合的模块设计更容易重用和扩展,因为它们相对独立并允许进行更改而不影响其他部分。实现低耦合的模块设计可以帮助减少代码的复杂度并提高可重用性。例如,一个低耦合的模块可以更容易地在其他项目中重用,因为它不会对其他模块产生影响,可以独立地进行修改和扩展。

使用设计模式可以帮助开发人员实现高内聚和低耦合的设计,从而提高代码的可维护性和可重用性。设计模式是一些被广泛应用于软件开发中的解决特定问题的方案。它们是经验丰富的程序员和软件设计师发现和总结的一些最佳实践,可以帮助开发人员更有效地解决各种问题。使用设计模式,可以提高代码的可读性、可维护性和可扩展性,同时还可以降低代码的复杂度和错误率。设计模式是实现高内聚和低耦合的理想方式之一,因为它们提供了一些经过验证的最佳实践,可以帮助开发人员更好地处理代码中的复杂关系。

Java中使用设计模式的重要性:

  • 提高代码的可读性和可维护性:通过使用设计模式,可以使代码更易于理解和修改,从而提高代码的可读性和可维护性。
  • 降低代码的复杂度和错误率:设计模式提供了一些经过验证的最佳实践,可以帮助开发人员更好地处理代码中的复杂关系,并减少代码的错误和复杂性。
  • 提高代码的复用性和扩展性:通过使用设计模式,可以将代码组织成可重用和可扩展的模块,从而提高代码的复用性和扩展性。
  • 与其他开发人员更好地合作:设计模式是一些被广泛应用于软件开发中的解决特定问题的方案。通过使用设计模式,可以使代码更易于理解和修改,从而使开发人员更容易合作开发项目。

因此,在Java开发中,使用设计模式是非常重要的,可以帮助开发人员提高代码的质量和可重用性。但是,需要注意的是,设计模式并不是一种万能的解决方案,需要根据具体的场景和需求进行选择和应用。

java中使用设计模式的目的和优点

设计模式的目的是提高代码的质量和可重用性。通过使用设计模式,可以遵循经过验证的最佳实践,在设计和实现软件时实现高内聚和低耦合的设计,从而减少代码的错误和复杂性,提高代码的可读性和可维护性,同时也可以提高代码的复用性和扩展性。

在软件设计中,高内聚和低耦合是非常重要的概念。高内聚是指模块内的元素相互关联度高,共同完成一个特定的任务。这意味着高内聚的模块设计更容易理解和维护,因为它们处理的问题更具体和清晰。实现高内聚的模块设计有助于减少代码中的混乱和错误,同时也可以提高代码的可读性和可维护性。例如,一个高内聚的模块可以更容易地测试和调试,因为它的功能更加明确,不需要涉及其他功能。

相反,低耦合是指模块之间的关系简单,尽可能少地相互影响。这意味着低耦合的模块设计更容易重用和扩展,因为它们相对独立并允许进行更改而不影响其他部分。实现低耦合的模块设计可以帮助减少代码的复杂度并提高可重用性。例如,一个低耦合的模块可以更容易地在其他项目中重用,因为它不会对其他模块产生影响,可以独立地进行修改和扩展。

使用设计模式可以帮助开发人员实现高内聚和低耦合的设计,从而提高代码的可维护性和可重用性。设计模式是一些被广泛应用于软件开发中的解决特定问题的方案。它们是经验丰富的程序员和软件设计师发现和总结的一些最佳实践,可以帮助开发人员更有效地解决各种问题。使用设计模式,可以提高代码的可读性、可维护性和可扩展性,同时还可以降低代码的复杂度和错误率。设计模式是实现高内聚和低耦合的理想方式之一,因为它们提供了一些经过验证的最佳实践,可以帮助开发人员更好地处理代码中的复杂关系。



设计原则

单一职责原则 (SRP)

一个类应该只有一个引起它变化的原因。换句话说,一个类应该只有一个职责。

例如,一个用于读取和写入文件的类应该只负责读取和写入文件,而不应该包含任何与文件读写无关的逻辑。

class FileReader {
    public void readFile(String fileName) {
        // read file logic
    }

    public void writeFile(String fileName, String content) {
        // write file logic
    }
}

开放封闭原则 (OCP)

软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。这意味着,当需要添加新功能时,不应该修改现有代码,而应该通过扩展现有代码来实现。

例如,一个用于计算图形面积的类应该能够计算不同类型的图形面积,而不需要修改现有代码。

interface Shape {
    double getArea();
}

class Rectangle implements Shape {
    double width;
    double height;

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

class Circle implements Shape {
    double radius;

    public double getArea() {
        return Math.PI * radius * radius;
    }
}

里氏替换原则 (LSP)

子类应该能够替换它们的父类并保持程序的正确性。换句话说,派生类应该能够被当作它们的基类使用。

例如,一个用于计算图形面积的类应该能够接受任意实现了该类的接口的图形类型,而不仅仅是特定的图形类型。

interface Shape {
    double getArea();
}

class Rectangle implements Shape {
    double width;
    double height;

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

class Circle implements Shape {
    double radius;

    public double getArea() {
        return Math.PI * radius * radius;
    }
}

class AreaCalculator {
    public double calculateArea(Shape shape) {
        return shape.getArea();
    }
}

接口隔离原则 (ISP)

客户端不应该强制依赖它们不需要的接口。换句话说,一个类不应该强制实现它不需要的接口。

例如,一个用于绘制图形的类应该只需要实现绘制图形的接口,而不需要实现其他不必要的接口。

interface Shape {
    void draw();
}

interface Color {
    void fill();
}

class Rectangle implements Shape {
    public void draw() {
        // draw rectangle logic
    }
}

class Circle implements Shape {
    public void draw() {
        // draw circle logic
    }
}

class Red implements Color {
    public void fill() {
        // fill with red color logic
    }
}

class ShapeDrawer {
    public void drawShape(Shape shape) {
        shape.draw();
    }
}

依赖倒置原则 (DIP)

高层模块不应该依赖于低层模块。它们应该依赖于抽象,而不是具体的实现。

例如,一个用于发送电子邮件的类应该依赖于一个抽象的邮件发送器接口,而不是具体的邮件发送器实现。

interface EmailSender {
    void send(String to, String subject, String body);
}

class SmtpEmailSender implements EmailSender {
    public void send(String to, String subject, String body) {
        // send email using SMTP protocol
    }
}

class SendGridEmailSender implements EmailSender {
    public void send(String to, String subject, String body) {
        // send email using SendGrid API
    }
}

class EmailService {
    private EmailSender sender;

    public EmailService(EmailSender sender) {
        this.sender = sender;
    }

    public void sendEmail(String to, String subject, String body) {
        sender.send(to, subject, body);
    }
}

迪米特法则 (LoD)

一个对象应该对其他对象有最少的了解。换句话说,一个对象应该只和它的直接朋友交流。

例如,一个用于购物车结算的类应该只与购物车和商品类交互,而不需要了解其他无关的类。

class Cart {
    List<Item> items;

    public void addItem(Item item) {
        items.add(item);
    }

    public void removeItem(Item item) {
        items.remove(item);
    }

    public double getTotal() {
        double total = 0;
        for (Item item : items) {
            total += item.getPrice();
        }
        return total;
    }
}

class Item {
    String name;
    double price;

    public double getPrice() {
        return price;
    }
}

class CheckoutService {
    public void checkout(Cart cart) {
        double total = cart.getTotal();
        // process payment and shipping
    }
}

合成复用原则 (CRP)

在软件设计中,应该尽量使用合成/聚合关系,而不是继承关系来实现代码的复用。这意味着,尽量将代码组织成小的、独立的模块,并将这些模块组合成更大的、复杂的模块。

例如,一个用于处理订单的类应该将支付和配送的逻辑分别封装成独立的模块,并通过合成关系来组合这些模块,而不是通过继承关系来实现。

interface PaymentService {
    void processPayment(Order order);
}

interface ShippingService {
    void ship(Order order);
}

class Order {
    List<Item> items;
    PaymentService paymentService;
    ShippingService shippingService;

    public void addItem(Item item) {
        items.add(item);
    }

    public void removeItem(Item item) {
        items.remove(item);
    }

    public double getTotal() {
        double total = 0;
        for (Item item : items) {
            total += item.getPrice();
        }
        return total;
    }

    public void processPayment() {
        paymentService.processPayment(this);
    }

    public void ship() {
        shippingService.ship(this);
    }
}

class Item {
    String name;
    double price;

    public double getPrice() {
        return price;
    }
}

class PayPalPaymentService implements PaymentService {
    public void processPayment(Order order) {
        // process payment using PayPal API
    }
}

class FedExShippingService implements ShippingService {
    public void ship(Order order) {
        // ship using FedEx API
    }
}

使用合成/聚合关系可以帮助减少代码的耦合性,并提高代码的可重用性和可维护性。因为每个模块都是独立的,所以它们可以在不影响其他模块的情况下进行修改和扩展。同时,合成/聚合关系也使代码更易于理解和测试,因为每个模块都有明确的职责和功能。



设计模式类型

设计模式是一些被广泛应用于软件开发中的解决特定问题的方案。设计模式可以分为三种类型:创建型模式、结构型模式和行为型模式。

创建型模式

创建型模式用于处理对象的创建过程,并提高对象的灵活性和可复用性。创建型模式包括以下几种:

  • 工厂方法模式(Factory Method Pattern)
  • 抽象工厂模式(Abstract Factory Pattern)
  • 单例模式(Singleton Pattern)
  • 建造者模式(Builder Pattern)
  • 原型模式(Prototype Pattern)

结构型模式

结构型模式用于处理对象之间的关系,并提高对象的组合和复用性。结构型模式包括以下几种:

  • 适配器模式(Adapter Pattern)
  • 桥接模式(Bridge Pattern)
  • 组合模式(Composite Pattern)
  • 装饰器模式(Decorator Pattern)
  • 外观模式(Facade Pattern)
  • 享元模式(Flyweight Pattern)
  • 代理模式(Proxy Pattern)

行为型模式

行为型模式用于处理对象之间的交互,并提高对象的灵活性和可复用性。行为型模式包括以下几种:

  • 职责链模式(Chain of Responsibility Pattern)
  • 命令模式(Command Pattern)
  • 解释器模式(Interpreter Pattern)
  • 迭代器模式(Iterator Pattern)
  • 中介者模式(Mediator Pattern)
  • 备忘录模式(Memento Pattern)
  • 观察者模式(Observer Pattern)
  • 状态模式(State Pattern)
  • 策略模式(Strategy Pattern)
  • 模板方法模式(Template Method Pattern)
  • 访问者模式(Visitor Pattern)

以上是常见的设计模式类型,它们可以帮助开发人员更好地应对不同的软件设计问题,提高代码的可读性、可维护性和可扩展性。



创建型模式

单例模式

单例模式是一种创建型模式,它保证一个类只有一个实例,并提供了一个访问它的全局访问点。在软件设计中,单例模式是一种常用的模式,它在许多场景下都能发挥重要作用。

实现

单例模式的实现方式有多种,其中最常见的是使用静态变量或枚举类型。静态变量的实现方式是在类中定义一个私有的静态变量,在第一次调用时初始化,之后每次调用都返回同一个实例。以下是一个使用静态变量的实现方式:

class Singleton {
    private static Singleton instance;

    private Singleton() {}

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

枚举类型的实现方式则更为简单,只需要定义一个枚举类型,并在其中定义一个实例即可。以下是一个使用枚举类型的实现方式:

enum Singleton {
    INSTANCE;
}

除了上述两种常见方式,还有其他的实现方式,例如双重校验锁、静态内部类等。不同的实现方式各有优缺点,需要根据具体的场景选择合适的方式。

设计原则

单例模式符合许多软件设计原则,例如单一职责原则、开放封闭原则和依赖倒置原则。它只负责创建和管理类的唯一实例,同时允许新增单例类的实例,而不需要修改现有代码。客户端只依赖于单例类的接口,而不依赖于具体的实现。

使用场景

单例模式适用于需要确保只有一个对象实例的情况,例如线程池、缓存、日志记录器等。在这些场景中,多个实例会带来额外的开销和不必要的风险,因此使用单例模式可以有效地解决这些问题。

在软件设计中,单例模式是一种非常有用的模式,它能够简化代码、提高性能,并保证程序的正确性和稳定性。因此,在适当的场景下,我们应该积极地使用单例模式,以实现更加优秀的软件设计。

如果您需要了解更多有关单例模式的详细信息,可以参考以下推荐资料:

  • 《设计模式:可复用面向对象软件的基础》(GoF) -《Head First 设计模式》(O'Reilly) -《Effective Java》(Joshua Bloch)

单例模式可以应用于许多情况,例如在需要确保只有一个对象实例的情况下使用。但是,在实际应用中,我们还需要考虑一些其他的因素,例如线程安全性、延迟加载等。因此,在使用单例模式时,我们需要根据具体的场景选择合适的实现方式,并在实现过程中注意一些常见的问题,以确保程序的正确性和稳定性。


工厂方法模式

工厂方法模式是一种创建型模式,它定义了一个用于创建对象的接口,但让子类决定实例化哪个类。工厂方法模式将对象的创建延迟到子类。

实现

工厂方法模式通过定义一个抽象工厂和多个具体工厂来实现。以下是一个简单的示例:

interface Animal {
    void say();
}

class Cat implements Animal {
    public void say() {
        System.out.println("Meow");
    }
}

class Dog implements Animal {
    public void say() {
        System.out.println("Woof");
    }
}

interface AnimalFactory {
    Animal createAnimal();
}

class CatFactory implements AnimalFactory {
    public Animal createAnimal() {
        return new Cat();
    }
}

class DogFactory implements AnimalFactory {
    public Animal createAnimal() {
        return new Dog();
    }
}

设计原则

工厂方法模式符合开放封闭原则,因为它允许新增具体工厂类,但不需要修改现有代码。它也符合依赖倒置原则,因为客户端只依赖于抽象工厂和抽象产品,而不依赖于具体的实现。

使用场景

工厂方法模式适用于需要动态创建对象的情况,例如在运行时根据用户输入的数据创建对象。


抽象工厂模式

抽象工厂模式是一种创建型模式,它提供了一组用于创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。抽象工厂模式将对象的创建延迟到子类。

实现

抽象工厂模式通过定义一个抽象工厂和多个具体工厂来实现。以下是一个简单的示例:

interface Animal {
    void say();
}

interface Plant {
    void grow();
}

interface AbstractFactory {
    Animal createAnimal();
    Plant createPlant();
}

class Cat implements Animal {
    public void say() {
        System.out.println("Meow");
    }
}

class Dog implements Animal {
    public void say() {
        System.out.println("Woof");
    }
}

class Tree implements Plant {
    public void grow() {
        System.out.println("Tree is growing");
    }
}

class Flower implements Plant {
    public void grow() {
        System.out.println("Flower is growing");
    }
}

class AnimalPlantFactory implements AbstractFactory {
    public Animal createAnimal() {
        return new Cat();
    }

    public Plant createPlant() {
        return new Tree();
    }
}

class DogFlowerFactory implements AbstractFactory {
    public Animal createAnimal() {
        return new Dog();
    }

    public Plant createPlant() {
        return new Flower();
    }
}

设计原则

抽象工厂模式符合开放封闭原则,因为它允许新增具体工厂类,但不需要修改现有代码。它也符合依赖倒置原则,因为客户端只依赖于抽象工厂和抽象产品,而不依赖于具体的实现。

使用场景

抽象工厂模式适用于需要创建一系列相关或相互依赖对象的情况,例如创建不同操作系统的 UI 组件。


建造者模式

建造者模式是一种创建型模式,它将对象的构造与表示分离,使得同样的构造过程可以创建不同的表示。

实现

建造者模式通过定义一个建造者接口和多个具体建造者来实现。以下是一个简单的示例:

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

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

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

    public void setPartC(String partC) {
        this.partC = partC;
    }

    public String getParts() {
        return "PartA: " + partA + ", PartB: " + partB + ", PartC: " + partC;
    }
}

interface Builder {
    void buildPartA();
    void buildPartB();
    void buildPartC();
    Product getProduct();
}

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

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

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

    public void buildPartC() {
        product.setPartC("C");
    }

    public Product getProduct() {
        return product;
    }
}

class Director {
    public void construct(Builder builder) {
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
    }
}

设计原则

建造者模式符合单一职责原则,因为它将对象的构造与表示分离,使得每个类只需要负责一个方面的功能。它也符合开放封闭原则,因为新增具体建造者类不需要修改现有代码。此外,它也符合依赖倒置原则,因为客户端只依赖于建造者接口,而不依赖于具体的实现。

使用场景

建造者模式适用于需要创建复杂对象的情况,例如汽车、电脑等。


原型模式

原型模式是一种创建型模式,它允许复制已有对象来创建新对象,而无需重新实例化和初始化。

实现

原型模式通过定义一个抽象原型和多个具体原型来实现。以下是一个简单的示例:

abstract class Prototype implements Cloneable {
    public abstract Prototype clone();
}

class ConcretePrototype extends Prototype {
    public Prototype clone() {
        try {
            return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

设计原则

原型模式符合单一职责原则,因为它将对象的创建和复制分离。它也符合开放封闭原则,因为新增具体原型类不需要修改现有代码。此外,它也符合依赖倒置原则,因为客户端只依赖于抽象原型,而不依赖于具体的实现。

使用场景

原型模式适用于创建成本较高、初始化较复杂或需要频繁创建的对象,例如数据库连接、线程等。



结构型模式

结构型模式是一种用于设计对象和类的模式,它们描述了如何将对象和类组合成更大的结构,并提供了一种简化结构的方式。结构型模式通常通过创建类和对象之间的关系来实现,这些关系可以是继承、组合或委托。

适配器模式

适配器模式是一种结构型模式,它允许将接口不兼容的类组合在一起。适配器模式通过创建一个中间层来转换接口,使得不兼容的类可以一起工作。

实现

适配器模式通过定义一个适配器类来实现。以下是一个简单的示例:

interface Target {
    void request();
}

class Adaptee {
    void specificRequest() {
        // do something
    }
}

class Adapter implements Target {
    private Adaptee adaptee;

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

    public void request() {
        adaptee.specificRequest();
    }
}

设计原则

适配器模式符合开放封闭原则,因为它允许新增适配器类,但不需要修改现有代码。它也符合依赖倒置原则,因为客户端只依赖于目标接口,而不依赖于具体的实现。

使用场景

适配器模式适用于需要将接口不兼容的类组合在一起的情况,例如使用已有的类库或组件。


桥接模式

桥接模式是一种结构型模式,它将抽象与实现分离,使得它们可以独立地变化。桥接模式通过使用组合来实现这种分离。

实现

桥接模式通过定义一个抽象类和多个具体实现类来实现。以下是一个简单的示例:

interface Implementor {
    void operationImpl();
}

abstract class Abstraction {
    protected Implementor implementor;

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

    abstract void operation();
}

class ConcreteImplementorA implements Implementor {
    public void operationImpl() {
        // do something
    }
}

class ConcreteImplementorB implements Implementor {
    public void operationImpl() {
        // do something
    }
}

class RefinedAbstraction extends Abstraction {
    RefinedAbstraction(Implementor implementor) {
        super(implementor);
    }

    void operation() {
        implementor.operationImpl();
    }
}

设计原则

桥接模式符合单一职责原则,因为它将抽象与实现分离,使得每个类只需要负责一个方面的功能。它也符合开放封闭原则,因为它允许新增实现类,但不需要修改现有代码。此外,它也符合依赖倒置原则,因为客户端只依赖于抽象类和接口,而不依赖于具体的实现。

使用场景

桥接模式适用于需要将抽象与实现分离的情况,例如在 GUI 设计中,将控件与平台相关的实现分离。


组合模式

组合模式是一种结构型模式,它允许将对象组合成树形结构来表示整体-部分关系。组合模式通过使用递归来实现这种结构。

实现

组合模式通过定义一个抽象类和多个具体类来实现。以下是一个简单的示例:

abstract class Component {
    abstract void operation();
}

class Leaf extends Component {
    void operation() {
        // do something
    }
}

class Composite extends Component {
    private List<Component> children = new ArrayList<Component>();

    void add(Component component) {
        children.add(component);
    }

    void remove(Component component) {
        children.remove(component);
    }

    void operation() {
        for (Component component : children) {
            component.operation();
        }
    }
}

设计原则

组合模式符合单一职责原则,因为它将组合对象和叶子对象分开处理。它也符合开放封闭原则,因为它允许新增叶子类和组合类,但不需要修改现有代码。此外,它也符合依赖倒置原则,因为客户端只依赖于抽象类和接口,而不依赖于具体的实现。


外观模式

外观模式是一种结构型模式,它为复杂的子系统提供一个简单的接口,从而使得外部调用方便使用。

实现

外观模式通过定义一个外观类来实现。以下是一个简单的示例:

class SubsystemA {
    void operationA() {
        // do something
    }
}

class SubsystemB {
    void operationB() {
        // do something
    }
}

class SubsystemC {
    void operationC() {
        // do something
    }
}

class Facade {
    private SubsystemA subsystemA = new SubsystemA();
    private SubsystemB subsystemB = new SubsystemB();
    private SubsystemC subsystemC = new SubsystemC();

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

设计原则

外观模式符合单一职责原则,因为它将复杂的子系统封装在一个外观类中。它也符合开放封闭原则,因为新增子系统不需要修改现有代码。此外,它也符合依赖倒置原则,因为客户端只依赖于外观类,而不依赖于具体的子系统。

使用场景

外观模式适用于需要使用复杂子系统的情况,例如操作系统 API。


享元模式

享元模式是一种结构型模式,它通过共享对象来减少内存使用和提高性能。

实现

享元模式通过定义一个享元工厂和多个共享对象来实现。以下是一个简单的示例:

class Flyweight {
    private String intrinsicState;

    Flyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }

    void operation(String extrinsicState) {
        System.out.println("Intrinsic state: " + intrinsicState);
        System.out.println("Extrinsic state: " + extrinsicState);
    }
}

class FlyweightFactory {
    private Map<String, Flyweight> flyweights = new HashMap<>();

    Flyweight getFlyweight(String key) {
        if (!flyweights.containsKey(key)) {
            flyweights.put(key, new Flyweight(key));
        }
        return flyweights.get(key);
    }
}

设计原则

享元模式符合单一职责原则,因为它将共享对象的创建和使用分离。它也符合开放封闭原则,因为新增共享对象不需要修改现有代码。此外,它也符合依赖倒置原则,因为客户端只依赖于享元工厂,而不依赖于具体的共享对象。

使用场景

享元模式适用于需要创建大量相似对象的情况,例如文本编辑器中的字符。


代理模式

代理模式是一种结构型模式,它为其他对象提供一种代理以控制对这个对象的访问。

实现

代理模式通过定义一个代理类来实现。以下是一个简单的示例:

interface Subject {
    void request();
}

class RealSubject implements Subject {
    public void request() {
        // do something
    }
}

class Proxy implements Subject {
    private RealSubject realSubject;

    Proxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    public void request() {
        // do something before
        realSubject.request();
        // do something after
    }
}

设计原则

代理模式符合单一职责原则,因为它将代理对象的创建和使用分离。它也符合开放封闭原则,因为新增代理类不需要修改现有代码。此外,它也符合依赖倒置原则,因为客户端只依赖于抽象主题和代理类,而不依赖于具体的实现。

使用场景

代理模式适用于需要控制对一个对象的访问的情况,例如需要限制访问权限或记录访问日志等。



行为型模式

行为型模式是一种用于设计对象和类的模式,它们描述了对象和类之间的通信方式,并提供了一种简化通信的方式。行为型模式通常通过定义对象和类之间的关系来实现,这些关系可以是继承、组合或委托。

职责链模式

职责链模式是一种行为型模式,它允许多个对象处理同一个请求,从而避免请求发送者和接收者之间的直接耦合关系。职责链模式通过使用链式结构来实现这种请求处理。

实现

职责链模式通过定义一个抽象处理者和多个具体处理者来实现。以下是一个简单的示例:

abstract class Handler {
    protected Handler successor;

    void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    abstract void handleRequest(int request);
}

class ConcreteHandlerA extends Handler {
    void handleRequest(int request) {
        if (request < 10) {
            // handle the request
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

class ConcreteHandlerB extends Handler {
    void handleRequest(int request) {
        if (request < 20) {
            // handle the request
        } else if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

设计原则

职责链模式符合开放封闭原则,因为它允许新增处理者,但不需要修改现有代码。它也符合依赖倒置原则,因为客户端只依赖于抽象处理者,而不依赖于具体的实现。

使用场景

职责链模式适用于需要多个对象处理同一个请求的情况,例如在一个工作流程中,需要多个部门审核一个申请。

命令模式

命令模式是一种行为型模式,它允许将请求封装成对象,从而使得请求发送者和接收者之间的耦合关系变得松散。命令模式通过使用命令对象和接收者对象来实现这种封装。

实现

命令模式通过定义一个抽象命令和多个具体命令来实现。以下是一个简单的示例:

interface Command {
    void execute();
}

class ConcreteCommand implements Command {
    private Receiver receiver;

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

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

class Receiver {
    void action() {
        // do something
    }
}

class Invoker {
    private Command command;

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

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

设计原则

命令模式符合开放封闭原则,因为它允许新增命令类,但不需要修改现有代码。它也符合依赖倒置原则,因为客户端只依赖于抽象命令,而不依赖于具体的实现。

使用场景

命令模式适用于需要将请求封装成对象的情况,例如撤销和重做操作、日志记录等。

解释器模式

解释器模式是一种行为型模式,它定义了一种语言和它的解释器,用来解释该语言中的表达式。

实现

解释器模式通过定义一个抽象解释器和多个具体解释器来实现。以下是一个简单的示例:

interface Expression {
    void interpret(Context context);
}

class TerminalExpression implements Expression {
    private String data;

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

    public void interpret(Context context) {
        if (context.getExpression().contains(data)) {
            // do something
        }
    }
}

class NonterminalExpression implements Expression {
    private Expression expression1;
    private Expression expression2;

    NonterminalExpression(Expression expression1, Expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }

    public void interpret(Context context) {
        expression1.interpret(context);
        expression2.interpret(context);
    }
}

class Context {
    private String expression;

    Context(String expression) {
        this.expression = expression;
    }

    String getExpression() {
        return expression;
    }
}

设计原则

解释器模式符合开放封闭原则,因为它允许新增解释器,但不需要修改现有代码。它也符合依赖倒置原则,因为客户端只依赖于抽象解释器,而不依赖于具体的实现。

使用场景

解释器模式适用于需要解释一种语言或表达式的情况,例如正则表达式和 SQL 语句。

迭代器模式

迭代器模式是一种行为型模式,它提供一种方法来访问一个容器对象中的各个元素,而不需要暴露该对象的内部结构。

实现

迭代器模式通过定义一个抽象迭代器和多个具体迭代器来实现。以下是一个简单的示例:

interface Iterator {
    boolean hasNext();
    Object next();
}

class ConcreteIterator implements Iterator {
    private List<Object> list;
    private int index;

    ConcreteIterator(List<Object> list) {
        this.list = list;
    }

    public boolean hasNext() {
        return index < list.size();
    }

    public Object next() {
        if (hasNext()) {
            return list.get(index++);
        } else {
            return null;
        }
    }
}

class Aggregate {
    private List<Object> list = new ArrayList<>();

    void add(Object object) {
        list.add(object);
    }

    void remove(Object object) {
        list.remove(object);
    }

    Iterator createIterator() {
        return new ConcreteIterator(list);
    }
}

设计原则

迭代器模式符合单一职责原则,因为它将遍历一个容器对象的任务分离出来。它也符合开放封闭原则,因为可以新增具体迭代器,但不需要修改现有代码。此外,它也符合依赖倒置原则,因为客户端只依赖于抽象迭代器,而不依赖于具体的实现。

使用场景

迭代器模式适用于需要遍历一个容器对象中的元素的情况,例如在一个图形界面中遍历各个控件。

中介者模式

中介者模式是一种行为型模式,它定义了一种封装一组对象如何交互的对象。中介者使对象之间的通信变得松散,从而使其更易于维护和扩展。

实现

中介者模式通过定义一个抽象中介者和多个具体同事类来实现。以下是一个简单的示例:

interface Mediator {
    void send(String message, Colleague colleague);
}

class ConcreteMediator implements Mediator {
    private Colleague colleague1;
    private Colleague colleague2;

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

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

    public void send(String message, Colleague colleague) {
        if (colleague == colleague1) {
            colleague2.receive(message);
        } else {
            colleague1.receive(message);
        }
    }
}

class Colleague {
    private Mediator mediator;

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

    void send(String message) {
        mediator.send(message, this);
    }

    void receive(String message) {
        // do something
    }
}

设计原则

中介者模式符合单一职责原则,因为它将对象之间的通信集中到一个对象中。它也符合开放封闭原则,因为新增同事类不需要修改现有代码。此外,它也符合依赖倒置原则,因为客户端只依赖于抽象中介者,而不依赖于具体的实现。

使用场景

中介者模式适用于多个对象之间需要进行复杂通信的情况,例如在一个大型图形界面中,需要让多个控件之间进行交互。

备忘录模式

备忘录模式是一种行为型模式,它允许捕获和恢复对象的内部状态,而不破坏其封装性。

实现

备忘录模式通过定义一个备忘录和一个负责人来实现。以下是一个简单的示例:

class Memento {
    private String state;

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

    String getState() {
        return state;
    }
}

class Originator {
    private String state;

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

    String getState() {
        return state;
    }

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

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

class Caretaker {
    private Memento memento;

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

    Memento retrieveMemento() {
        return memento;
    }
}

设计原则

备忘录模式符合单一职责原则,因为它将备忘录对象和负责人对象分离。它也符合开放封闭原则,因为可以新增备忘录类和负责人类,但不需要修改现有代码。此外,它也符合依赖倒置原则,因为客户端只依赖于备忘录和负责人的抽象接口,而不依赖于具体的实现。

使用场景

备忘录模式适用于需要捕获和恢复对象内部状态的情况,例如在撤销和重做操作中,或者在需要保存一个对象的快照以便将来恢复时。

观察者模式

观察者模式是一种行为型模式,它定义了一种一对多的依赖关系,使得当一个对象改变状态时,所有依赖于它的对象都会被通知并自动更新。

实现

观察者模式通过定义一个抽象主题和多个具体观察者来实现。以下是一个简单的示例:

interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers();
}

class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String state;

    void attach(Observer observer) {
        observers.add(observer);
    }

    void detach(Observer observer) {
        observers.remove(observer);
    }

    void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(state);
        }
    }

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

interface Observer {
    void update(String state);
}

class ConcreteObserver implements Observer {
    private String state;

    void update(String state) {
        this.state = state;
        // do something
    }
}

设计原则

观察者模式符合单一职责原则,因为它将主题和观察者的职责分开。它也符合开放封闭原则,因为可以新增观察者,但不需要修改现有代码。此外,它也符合依赖倒置原则,因为客户端只依赖于抽象主题和观察者,而不依赖于具体的实现。

使用场景

观察者模式适用于一个对象的状态改变需要通知多个对象的情况,例如在一个股票市场中,需要通知多个投资者股价的变化。

状态模式

状态模式是一种行为型模式,它允许一个对象在其内部状态发生改变时改变其行为。

实现

状态模式通过定义一个抽象状态和多个具体状态来实现。以下是一个简单的示例:

interface State {
    void handle();
}

class ConcreteStateA implements State {
    void handle() {
        // do something
    }
}

class ConcreteStateB implements State {
    void handle() {
        // do something
    }
}

class Context {
    private State state;

    void setState(State state) {
        this.state = state;
    }

    void request() {
        state.handle();
    }
}

设计原则

状态模式符合开放封闭原则,因为它允许新增状态类,但不需要修改现有代码。它也符合依赖倒置原则,因为客户端只依赖于抽象状态,而不依赖于具体的实现。

使用场景

状态模式适用于一个对象需要在其内部状态发生改变时改变其行为的情况,例如在一个订单状态发生变化时,需要改变其处理方式。

策略模式

策略模式是一种行为型模式,它定义了一族算法,将每个算法都封装起来,并使它们之间可以互换。

实现

策略模式通过定义一个抽象策略和多个具体策略来实现。以下是一个简单的示例:

interface Strategy {
    void execute();
}

class ConcreteStrategyA implements Strategy {
    void execute() {
        // do something
    }
}

class ConcreteStrategyB implements Strategy {
    void execute() {
        // do something
    }
}

class Context {
    private Strategy strategy;

    void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    void executeStrategy() {
        strategy.execute();
    }
}

设计原则

策略模式符合开放封闭原则,因为它允许新增策略类,但不需要修改现有代码。它也符合依赖倒置原则,因为客户端只依赖于抽象策略,而不依赖于具体的实现。

使用场景

策略模式适用于需要在多个算法之间切换的情况,例如在一个游戏中,需要根据不同的场景使用不同的 AI 算法。

模板方法模式

模板方法模式是一种行为型模式,它定义了一个算法的骨架,将一些步骤延迟到子类中实现,从而使得子类可以改变算法的某些特定步骤,而不需要改变算法的结构。

实现

模板方法模式通过定义一个抽象模板和多个具体模板来实现。以下是一个简单的示例:

abstract class AbstractTemplate {
    void templateMethod() {
        step1();
        step2();
        step3();
    }

    abstract void step1();
    abstract void step2();
    abstract void step3();
}

class ConcreteTemplate extends AbstractTemplate {
    void step1() {
        // do something
    }

    void step2() {
        // do something
    }

    void step3() {
        // do something
    }
}

设计原则

模板方法模式符合开放封闭原则,因为它允许新增具体模板,但不需要修改现有代码。它也符合依赖倒置原则,因为客户端只依赖于抽象模板,而不依赖于具体的实现。

使用场景

模板方法模式适用于需要在多个算法中共享一些代码的情况,例如在一个文本编辑器中,需要在多个文档中实现相同的保存流程。

访问者模式

访问者模式是一种行为型模式,它允许在不改变现有类的情况下定义新的操作。

实现

访问者模式通过定义一个抽象访问者和多个具体访问者来实现。以下是一个简单的示例:

interface Visitor {
    void visit(ConcreteElementA element);
    void visit(ConcreteElementB element);
}

class ConcreteVisitor implements Visitor {
    void visit(ConcreteElementA element) {
        // do something
    }

    void visit(ConcreteElementB element) {
        // do something
    }
}

interface Element {
    void accept(Visitor visitor);
}

class ConcreteElementA implements Element {
    void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

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

设计原则

访问者模式符合开放封闭原则,因为它允许新增具体访问者,但不需要修改现有代码。它也符合依赖倒置原则,因为客户端只依赖于抽象访问者,而不依赖于具体的实现。

使用场景

访问者模式适用于需要在多个类中执行相同操作的情况,例如在一个图像处理软件中,需要对多个图像对象执行相同的滤镜操作。