java有多少种设计模式?


Java语言中常用的设计模式有23种,它们分别属于三个不同的分类,即创建型模式(Creational Patterns)、结构型模式(Structural Patterns)和行为型模式(Behavioral Patterns)。下面是这23种设计模式的简要介绍:

创建型模式(Creational Patterns):

  1. 工厂方法模式(Factory Method Pattern)
  2. 抽象工厂模式(Abstract Factory Pattern)
  3. 单例模式(Singleton Pattern)
  4. 建造者模式(Builder Pattern)
  5. 原型模式(Prototype Pattern)

结构型模式(Structural Patterns):

  1. 适配器模式(Adapter Pattern)
  2. 桥接模式(Bridge Pattern)
  3. 组合模式(Composite Pattern)
  4. 装饰者模式(Decorator Pattern)
  5. 外观模式(Facade Pattern)
  6. 享元模式(Flyweight Pattern)
  7. 代理模式(Proxy Pattern)

行为型模式(Behavioral Patterns):

  1. 责任链模式(Chain of Responsibility Pattern)
  2. 命令模式(Command Pattern)
  3. 解释器模式(Interpreter Pattern)
  4. 迭代器模式(Iterator Pattern)
  5. 中介者模式(Mediator Pattern)
  6. 备忘录模式(Memento Pattern)
  7. 观察者模式(Observer Pattern)
  8. 状态模式(State Pattern)
  9. 策略模式(Strategy Pattern)
  10. 模板方法模式(Template Method Pattern)
  11. 访问者模式(Visitor Pattern)

这些设计模式提供了一种在软件开发中常见问题的解决方案,并且在实践中被广泛应用。每个模式都有自己的特定情境和使用方式,开发人员可以根据需要选择合适的设计模式来提高代码的可维护性、灵活性和可扩展性。

下面开始一一展开:

创建型模式(Creational Patterns):

01.工厂方法模式(Factory Method Pattern)

工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个创建对象的接口,但将具体的对象实例化的过程延迟到子类中进行。这样可以使得一个类的实例化由子类决定,而不是在父类中直接实例化。

工厂方法模式的核心思想是将对象的创建和使用分离,通过引入一个抽象的工厂类和具体的工厂子类来实现。工厂类定义了一个抽象的工厂方法,该方法由子类实现,用于创建具体的产品对象。客户端通过调用工厂方法来获取所需的产品对象,而无需关心具体的产品类。

下面是工厂方法模式的一些关键角色:

  1. 抽象产品(Abstract Product):定义了产品的接口,所有具体产品类都实现了该接口。
  2. 具体产品(Concrete Product):具体的产品类,实现了抽象产品接口。
  3. 抽象工厂(Abstract Factory):定义了创建产品对象的工厂方法接口,可以是抽象类或接口。
  4. 具体工厂(Concrete Factory):具体的工厂类,实现了抽象工厂接口,负责创建具体的产品对象。

工厂方法模式的优点包括:

  • 将对象的创建和使用解耦,提供了更高的灵活性和可扩展性。
  • 符合开闭原则,即对扩展开放,对修改关闭。
  • 可以通过添加新的具体工厂和产品类来增加新的产品族,而无需修改已有代码。

工厂方法模式适用于以下情况:

  • 当一个类不知道它所需对象的具体类时。
  • 当一个类希望由其子类来指定所需对象时。
  • 当需要根据不同的条件创建不同的对象时。

总结来说,工厂方法模式通过定义一个工厂接口和具体的工厂子类,将对象的创建延迟到子类中实现,提供了一种灵活、可扩展的对象创建方式。它在实际开发中被广泛应用,用于解耦对象的创建和使用,并提供了更高的可定制性和扩展性。

02.抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种方式来创建一系列相关或依赖对象的家族,而不需要指定具体的类。

抽象工厂模式通过引入抽象工厂接口和具体工厂类来实现。抽象工厂接口定义了一组方法,用于创建一系列相关的产品对象。每个具体工厂类实现了抽象工厂接口,负责创建特定的产品家族。

在抽象工厂模式中,有以下几个关键角色:

  1. 抽象工厂(Abstract Factory):定义了创建产品对象的方法接口,可以是抽象类或接口。
  2. 具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体的产品对象。
  3. 抽象产品(Abstract Product):定义了产品的接口,所有具体产品类都实现了该接口。
  4. 具体产品(Concrete Product):具体的产品类,实现了抽象产品接口。

抽象工厂模式的优点包括:

  • 将对象的创建和使用解耦,客户端与具体产品的创建过程分离,提供了更高的灵活性和可扩展性。
  • 符合开闭原则,即对扩展开放,对修改关闭。
  • 可以确保创建的产品是相关的,保持产品家族的一致性。

抽象工厂模式适用于以下情况:

  • 当需要创建一系列相关或依赖的产品对象时。
  • 当希望客户端与具体产品的创建过程解耦时。
  • 当需要提供一组相关产品的家族,而不关心具体的实现类时。

总结来说,抽象工厂模式通过定义抽象工厂接口和具体工厂类,将对象的创建过程封装起来,提供了一种创建一系列相关或依赖对象的方式。它在实际开发中常用于创建产品家族,保持产品之间的一致性,并提供了灵活性和可扩展性。

03.单例模式(Singleton Pattern)

单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供全局访问该实例的方式。

单例模式的核心思想是通过限制类的实例化过程,保证在整个应用程序中只存在一个对象实例。通常情况下,单例模式使用一个私有的构造函数来防止类被直接实例化,然后提供一个静态方法或成员变量来获取该类的唯一实例。

下面是单例模式的一些关键要素:

  1. 私有构造函数(Private Constructor):单例类的构造函数应该是私有的,这样可以防止其他类直接实例化该类。
  2. 静态方法或成员变量(Static Method or Variable):单例类提供一个静态方法或静态成员变量,用于获取类的唯一实例。
  3. 延迟初始化(Lazy Initialization):单例对象通常是在首次访问时创建,而不是在应用程序启动时创建,以提高性能和资源利用率。
  4. 线程安全性(Thread Safety):在多线程环境下,需要考虑单例对象的线程安全性,确保只有一个实例被创建。

单例模式的优点包括:

  • 提供了对唯一实例的全局访问点,方便其他对象使用。
  • 确保在整个应用程序中只存在一个实例,避免了重复创建相同对象的开销。
  • 可以控制实例化过程,实现对单例对象的管理和控制。

单例模式适用于以下情况:

  • 当一个类只需要有一个实例,并且需要全局访问该实例时。
  • 当需要控制某个资源的共享访问时,如数据库连接池、线程池等。

然而,单例模式也有一些缺点,如可能引入全局状态、对扩展性的限制等。因此,在使用单例模式时需要谨慎考虑,并确保合理地使用该模式。

总结来说,单例模式通过限制类的实例化过程,确保在整个应用程序中只存在一个实例,并提供全局访问该实例的方式。它在实际开发中被广泛应用,用于管理全局资源、共享对象等场景。

04.建造者模式(Builder Pattern)

建造者模式(Builder Pattern)是一种创建型设计模式,它可以通过一步一步地构造复杂对象,将对象的构建过程与其表示分离开来。

建造者模式的核心思想是将一个复杂对象的构建过程分解为多个简单的步骤,由一个指导者(Director)按照特定的顺序调用建造者(Builder)来逐步构建对象。建造者模式通过将对象的构建过程和最终的表示分离,使得同样的构建过程可以创建不同的表示。

下面是建造者模式的一些关键要素:

  1. 产品类(Product):表示正在构建的复杂对象。
  2. 抽象建造者(Abstract Builder):定义了构建产品的接口,包括各个构建步骤的方法。
  3. 具体建造者(Concrete Builder):实现了抽象建造者接口,负责具体的构建过程和最终的产品返回。
  4. 指导者(Director):负责按照特定顺序调用建造者的方法来构建对象。

建造者模式的优点包括:

  • 将对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。
  • 可以更加精细地控制对象的构建过程,以满足不同的需求。
  • 提供了更好的封装性,隐藏了对象的构建细节。

建造者模式适用于以下情况:

  • 当需要创建的对象具有复杂的内部结构,并且需要一步一步地构建对象时。
  • 当需要创建不同表示的相似对象时,例如创建不同风格的产品。

总结来说,建造者模式通过一步一步地构建复杂对象,将对象的构建过程与其表示分离,提供了更好的封装性和灵活性。它在实际开发中被广泛应用,用于构建复杂的对象,特别是当对象的构建过程需要多个步骤、变化较大或存在多个变体时。

05.原型模式(Prototype Pattern)

原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制(克隆)现有对象来创建新的对象,而无需依赖显式的实例化过程。

原型模式的核心思想是使用一个原型对象作为基础,通过克隆来创建新的对象。原型对象是被复制的对象,它定义了一个克隆方法(通常为clone()),用于创建新的对象副本。通过复制原型对象,可以避免使用显式的实例化操作,从而提高对象的创建效率。

原型模式涉及以下几个关键要素:

  1. 抽象原型(Prototype):定义了一个克隆方法,用于创建新的对象副本。
  2. 具体原型(Concrete Prototype):实现了抽象原型接口,实现克隆方法。
  3. 客户端(Client):使用原型对象进行克隆来创建新的对象。

原型模式的优点包括:

  • 可以减少对象的创建过程,提高对象的创建效率。
  • 避免了显式的实例化操作,使得对象的创建更加灵活。
  • 可以在运行时动态地添加或删除原型对象。

原型模式适用于以下情况:

  • 当需要创建的对象和其创建过程相对固定,但需要频繁创建对象副本时。
  • 当对象的创建过程较为复杂,而希望通过克隆来简化创建操作。

需要注意的是,在使用原型模式时,原型对象必须实现克隆方法,且克隆方法的实现要注意深拷贝和浅拷贝的问题,以确保复制的对象是一个独立的新对象。

总结来说,原型模式通过复制现有对象来创建新的对象,避免了显式的实例化操作,提高了对象的创建效率。它在实际开发中常用于创建复杂对象或需要频繁创建对象副本的场景,提供了一种灵活、高效的对象创建方式。

结构型模式(Structural Patterns):

06.适配器模式(Adapter Pattern)

适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换为另一个客户端所期望的接口形式。它允许原本不兼容的类能够一起工作,通过适配器将它们之间的差异进行转换和适配。

适配器模式通常包含以下几个角色:

  1. 目标接口(Target Interface):客户端所期望的接口形式。适配器将原始接口转换为目标接口。

  2. 适配器(Adapter):实现目标接口,并且包含一个对原始类的引用。适配器通过调用原始类的方法来实现目标接口的方法,并进行适配转换。

  3. 原始类(Adaptee):需要被适配的类,其接口与目标接口不兼容。

适配器模式的工作流程如下:

  1. 客户端通过调用目标接口的方法来实现特定的功能。

  2. 适配器接收客户端的调用,然后将其转发给原始类。

  3. 原始类执行相应的操作,并将结果返回给适配器。

  4. 适配器将原始类返回的结果进行适配和转换,然后返回给客户端。

适配器模式的优点包括:

  • 通过适配器,可以使原本不兼容的类能够协同工作,增强了代码的复用性和灵活性。
  • 可以在不修改原始类的情况下实现接口的转换和适配。
  • 可以将不同的类集成到统一的接口中,简化了客户端的调用。

以下是一个简单的示例,展示了适配器模式的应用:

// 目标接口
trait MediaPlayer {
  def play(file: String): Unit
}

// 原始类
class AdvancedMediaPlayer {
  def playMp4(file: String): Unit = {
    println(s"Playing MP4 file: $file")
  }
}

// 适配器
class Mp4PlayerAdapter extends MediaPlayer {
  private val advancedPlayer: AdvancedMediaPlayer = new AdvancedMediaPlayer()

  override def play(file: String): Unit = {
    advancedPlayer.playMp4(file)
  }
}

// 客户端代码
val mediaPlayer: MediaPlayer = new Mp4PlayerAdapter()
mediaPlayer.play("movie.mp4")

在上面的示例中,我们有一个原始类 AdvancedMediaPlayer,它具有 playMp4 方法用于播放 MP4 文件。然而,我们的目标接口是 MediaPlayer,它具有 play 方法。

为了适配这两个不兼容的接口,我们创建了适配器 Mp4PlayerAdapter,它实现了目标接口 MediaPlayer,并包含了一个对原始类 AdvancedMediaPlayer 的引用。适配器将 play 方法的调用转发给原始类的 playMp4 方法,并进行适配转换。

在客户端代码中,我们创建了适配器的实例,并通过目标接口 MediaPlayer 的方法来播放 MP4 文件。通过适配器模式,我们可以将原始类的功能转换为客户端所期望的接口形式,实现了接口之间的适配和兼容。

适配器模式在实际开发中经常被用于以下情况:

  • 在使用现有类库时,如果接口与现有代码不兼容,可以使用适配器模式进行接口转换。
  • 在进行系统重构时,可以使用适配器模式来兼容旧代码和新代码之间的差异。
  • 在多个类之间需要进行接口统一时,可以使用适配器模式将它们转换为统一的接口。

需要注意的是,适配器模式应该被谨慎使用,避免过度使用适配器导致代码复杂性增加。在设计和使用时,需要考虑清楚适配器的职责和作用,并遵循单一职责原则和接口隔离原则。

07.桥接模式(Bridge Pattern)

桥接模式(Bridge Pattern)是一种结构型设计模式,用于将抽象部分与其具体实现部分分离,使它们能够独立变化。桥接模式通过将继承关系转化为关联关系,减少了抽象和实现之间的耦合,从而提高了系统的灵活性。

在桥接模式中,存在两个独立变化的维度:抽象部分和实现部分。抽象部分定义了高层的业务逻辑,而实现部分定义了具体的实现细节。通过桥接模式,这两个部分可以独立扩展,互不影响。

在Java中,桥接模式可以通过接口和实现类的组合来实现。具体来说,抽象部分定义一个抽象接口,而实现部分则提供具体的实现类。抽象部分中持有一个实现部分的引用,通过调用实现部分的方法来完成具体的业务逻辑。

下面是一个简单的示例代码,演示了桥接模式的实现:

// 实现部分接口
interface Implementor {
    void operationImpl();
}

// 具体实现类A
class ConcreteImplementorA implements Implementor {
    @Override
    public void operationImpl() {
        System.out.println("具体实现A的操作");
    }
}

// 具体实现类B
class ConcreteImplementorB implements Implementor {
    @Override
    public void operationImpl() {
        System.out.println("具体实现B的操作");
    }
}

// 抽象部分
abstract class Abstraction {
    protected Implementor implementor;

    public void setImplementor(Implementor implementor) {
        this.implementor = implementor;
    }

    public abstract void operation();
}

// 扩展抽象部分A
class RefinedAbstractionA extends Abstraction {
    @Override
    public void operation() {
        System.out.println("扩展抽象A的操作");
        implementor.operationImpl();
    }
}

// 扩展抽象部分B
class RefinedAbstractionB extends Abstraction {
    @Override
    public void operation() {
        System.out.println("扩展抽象B的操作");
        implementor.operationImpl();
    }
}

// 示例使用
public class Main {
    public static void main(String[] args) {
        Abstraction abstractionA = new RefinedAbstractionA();
        abstractionA.setImplementor(new ConcreteImplementorA());
        abstractionA.operation();

        Abstraction abstractionB = new RefinedAbstractionB();
        abstractionB.setImplementor(new ConcreteImplementorB());
        abstractionB.operation();
    }
}

输出结果:

扩展抽象A的操作
具体实现A的操作
扩展抽象B的操作
具体实现B的操作

在上述示例中,Implementor接口表示实现部分,ConcreteImplementorA和ConcreteImplementorB是具体的实现类。Abstraction抽象类表示抽象部分,RefinedAbstractionA和RefinedAbstractionB是对抽象部分的扩展。

在Main类中,通过创建具体的抽象部分对象(RefinedAbstractionA和RefinedAbstractionB),并将具体的实现部分对象(ConcreteImplementorA和ConcreteImplementorB)设置给它们,实现了抽象部分和实现部分的关联。然后,通过调用抽象部分的operation方法,实现了抽象部分和实现部分的协同工作。

通过桥接模式,可以在不修改现有代码的情况下,轻松地扩展抽象部分和实现部分,使它们可以独立变化。这种分离的设计可以提高系统的可维护性和可扩展性。

需要注意的是,桥接模式适用于当一个系统中存在多个维度的变化,并且每个维度都可以独立地变化时。它可以避免类爆炸的问题,提供更加灵活和可扩展的设计。然而,过度使用桥接模式可能会增加代码的复杂性,因此在使用时需要权衡利弊。

08.组合模式(Composite Pattern)

组合模式(Composite Pattern)是一种结构型设计模式,用于将对象组合成树形结构以表示"整体-部分"的层次关系。组合模式使得客户端可以统一处理单个对象和组合对象,而无需区分它们的差异,从而简化了客户端的代码。

在组合模式中,有两种主要的角色:

  1. 组件(Component):定义了组合对象和叶子对象的公共接口,可以是抽象类或接口。它声明了一些用于管理子对象的方法,例如添加子对象、删除子对象、获取子对象等。

  2. 组合对象(Composite):是由多个组件组成的复杂对象,可以包含其他组合对象和叶子对象。它实现了组件接口,并提供了对子对象的管理操作,例如添加子对象、删除子对象、获取子对象等。它可以递归地执行这些操作。

  3. 叶子对象(Leaf):是组合对象中的最小单位,不能包含其他组合对象。它实现了组件接口,但在其实现中可能不需要进行任何操作。

组合模式的关键思想是将对象组织成树形结构,并通过统一的接口对待组合对象和叶子对象。这样,客户端可以通过递归遍历整个树形结构,并对每个对象执行相应的操作,而无需关心对象的具体类型。

下面是一个示例代码,演示了组合模式的实现:

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

// 叶子对象
class Leaf implements Component {
    @Override
    public void operation() {
        System.out.println("执行叶子对象的操作");
    }
}

// 组合对象
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() {
        System.out.println("执行组合对象的操作");
        for (Component component : components) {
            component.operation();
        }
    }
}

// 示例使用
public class Main {
    public static void main(String[] args) {
        Component leaf1 = new Leaf();
        Component leaf2 = new Leaf();

        Composite composite1 = new Composite();
        composite1.addComponent(leaf1);
        composite1.addComponent(leaf2);

        Component leaf3 = new Leaf();

        Composite composite2 = new Composite();
        composite2.addComponent(leaf3);
        composite2.addComponent(composite1);

        composite2.operation();
    }
}

输出结果:

执行组合对象的操作
执行叶子对象的操作
执行叶子对象的操作

在上述示例中,Component接口定义了组合对象和叶子对象的公共操作。Leaf类是叶子对象的实现,它执行具体的操作。Composite类是组合对象的实现,它管理了一组子对象(可以是叶子对象或其他组合对象),并在operation方法中遍历并执行子对象的操作。

在示例的主函数中,首先创建了两个Leaf对象(leaf1和leaf2),然后创建了一个Composite对象(composite1),并将leaf1和leaf2添加到composite1中。接着,创建了一个Leaf对象(leaf3)和另一个Composite对象(composite2),并将leaf3和composite1添加到composite2中。最后,调用composite2的operation方法,触发了整个树形结构的遍历和操作。

通过组合模式,我们可以灵活地组织对象的层次结构,并统一对待组合对象和叶子对象。客户端可以通过操作顶层的组合对象,而无需了解其内部的具体结构,从而简化了客户端的代码。组合模式适用于处理具有层次结构的对象,例如树形结构、文件系统等。

需要注意的是,组合模式在增加新的组件类型时比较困难,因为需要修改抽象组件接口及其所有的子类。此外,组合模式可能导致系统中的对象数量增多,因为每个叶子对象都需要一个具体的实例。因此,在使用组合模式时需要权衡灵活性和系统复杂性之间的关系。

09.装饰者模式(Decorator Pattern)

装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许你在不改变现有对象结构的情况下,动态地将新功能附加到对象上。装饰者模式通过创建包装对象来实现这一点,这样可以在运行时添加、修改或删除对象的行为。

在装饰者模式中,有以下几个关键角色:

  1. 抽象组件(Component):定义了装饰者和被装饰者的共同接口,可以是抽象类或接口。它声明了被装饰者的基本操作方法。

  2. 具体组件(Concrete Component):实现了抽象组件接口,是被装饰者的原始对象。它定义了基本的功能。

  3. 抽象装饰者(Decorator):继承了抽象组件,并持有一个抽象组件的引用。它可以通过构造函数或Setter方法来注入被装饰者对象。它的目的是为了动态地添加额外的行为或修改原有的行为。

  4. 具体装饰者(Concrete Decorator):继承了抽象装饰者,并扩展了其功能。它可以在调用父类的方法之前或之后添加额外的行为。

装饰者模式的核心思想是通过嵌套组合来实现功能的动态扩展。具体的装饰者可以根据需要嵌套组合,从而实现对原始对象功能的多层次装饰。

下面是一个示例代码,演示了装饰者模式的实现:

// 抽象组件
interface Component {
    void operation();
}

// 具体组件
class ConcreteComponent implements Component {
    @Override
    public void operation() {
        System.out.println("执行具体组件的操作");
    }
}

// 抽象装饰者
abstract class Decorator implements Component {
    protected Component component;

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

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

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

    @Override
    public void operation() {
        super.operation();
        addAdditionalBehavior();
    }

    private void addAdditionalBehavior() {
        System.out.println("执行具体装饰者A附加的操作");
    }
}

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

    @Override
    public void operation() {
        super.operation();
        addAdditionalBehavior();
    }

    private void addAdditionalBehavior() {
        System.out.println("执行具体装饰者B附加的操作");
    }
}

// 示例使用
public class Main {
    public static void main(String[] args) {
        Component component = new ConcreteComponent();
           // 使用具体装饰者A装饰component
    Component decoratorA = new ConcreteDecoratorA(component);
    decoratorA.operation();

    System.out.println("--------");

    // 使用具体装饰者B装饰component
    Component decoratorB = new ConcreteDecoratorB(component);
    decoratorB.operation();

    System.out.println("--------");

    // 使用具体装饰者A和具体装饰者B同时装饰component
    Component decoratorAB = new ConcreteDecoratorA(new ConcreteDecoratorB(component));
    decoratorAB.operation();
}

输出结果:

执行具体组件的操作
执行具体装饰者A附加的操作
--------
执行具体组件的操作
执行具体装饰者B附加的操作
--------
执行具体组件的操作
执行具体装饰者B附加的操作
执行具体装饰者A附加的操作

在上述示例中,Component接口定义了被装饰者的操作。ConcreteComponent类是具体的组件,实现了Component接口。

Decorator抽象类是抽象装饰者,它继承了Component接口,并持有一个Component类型的引用。在其operation方法中,首先调用被装饰者的operation方法,然后添加了额外的行为。

ConcreteDecoratorA和ConcreteDecoratorB是具体的装饰者,它们继承了Decorator抽象类,并实现了自己的addAdditionalBehavior方法,用于添加额外的行为。

在示例的主函数中,首先创建了一个具体组件对象(ConcreteComponent),然后使用具体装饰者A(ConcreteDecoratorA)对该对象进行装饰,接着使用具体装饰者B(ConcreteDecoratorB)对该对象进行装饰,最后同时使用具体装饰者A和具体装饰者B对该对象进行装饰。

通过装饰者模式,我们可以动态地为对象添加新的功能,而无需修改原始对象的结构。这种灵活性使得装饰者模式在需要对对象进行多层次的动态扩展时非常有用。同时,装饰者模式遵循开闭原则,使得系统具有更好的可扩展性和可维护性。

10.外观模式(Facade Pattern)

外观模式(Facade Pattern)是一种结构型设计模式,它提供了一个简化的接口,用于访问复杂子系统的一组接口。外观模式通过定义一个高层接口,封装了子系统的复杂性,使得客户端能够更方便地使用子系统。

在外观模式中,有以下几个主要角色:

  1. 外观(Facade):它提供了一个简化的接口,用于访问子系统的功能。外观模式通常只有一个外观类,它将客户端的请求委派给子系统进行处理。

  2. 子系统(Subsystem):它是实际执行业务逻辑的组件集合。子系统可以由一个或多个类组成,它们协同工作以完成特定的任务。外观模式通过外观类将子系统的功能封装起来,对外部提供统一的接口。

  3. 客户端(Client):它通过外观类来访问子系统的功能,而不需要直接与子系统的类进行交互。

外观模式的核心思想是通过提供一个简化的接口,隐藏子系统的复杂性,使得客户端更容易使用子系统。外观模式可以降低客户端与子系统之间的耦合度,提供了一种高层次的抽象,使得客户端不需要了解子系统的内部结构和细节。

下面是一个示例代码,演示了外观模式的实现:

// 子系统A
class SubsystemA {
    public void operationA() {
        System.out.println("SubsystemA执行操作");
    }
}

// 子系统B
class SubsystemB {
    public void operationB() {
        System.out.println("SubsystemB执行操作");
    }
}

// 外观
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 Main {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.operation();
    }
}

输出结果:

SubsystemA执行操作
SubsystemB执行操作

在上述示例中,SubsystemA和SubsystemB是两个子系统,它们分别提供了自己的操作。Facade是外观类,它封装了SubsystemA和SubsystemB的功能,并提供了一个简化的接口operation。在Main类中,通过创建一个Facade对象,然后调用其operation方法,实现了对子系统功能的访问。

通过外观模式,客户端不需要直接与子系统的类进行交互,而是通过外观类来访问子系统的功能。这样可以降低客户端与子系统之间的耦合。

外观模式的优点包括:

  1. 简化接口:外观模式通过提供一个简化的接口,隐藏了子系统的复杂性,使得客户端更容易使用子系统。客户端只需与外观类进行交互,而无需了解子系统的内部结构和细节。

  2. 降低耦合度:外观模式可以降低客户端与子系统之间的耦合度。客户端只依赖于外观类,而不需要直接与子系统的类进行交互。这样,即使子系统发生变化,只需要调整外观类而不影响客户端。

  3. 提高可维护性:外观模式将子系统的功能封装在一个外观类中,使得子系统的变更更加集中和可控。如果子系统的接口或实现发生变化,只需修改外观类即可,而不需要修改客户端代码。

  4. 实现了松耦合:外观模式实现了子系统与客户端之间的松耦合。客户端只需要知道外观类的接口,而不需要了解子系统的具体实现。这样可以实现子系统和客户端的独立演化,提高系统的灵活性。

外观模式的适用场景包括:

  1. 当存在一个复杂的子系统,并且希望为客户端提供一个简化的接口来访问子系统时,可以使用外观模式。外观模式通过封装子系统的复杂性,简化了客户端的操作。

  2. 当需要将子系统的接口与实现分离,以便于独立演化和修改时,可以使用外观模式。外观模式将子系统的实现隐藏在外观类中,客户端只需要与外观类进行交互,这样可以实现子系统和客户端的解耦。

  3. 当希望将多个相关的子系统封装为一个统一的接口时,可以使用外观模式。外观模式可以将多个子系统的功能整合到一个外观类中,为客户端提供一个统一的接口,从而简化了客户端的调用。

  4. 当需要简化复杂系统的使用,并提供一种简单的入口点时,可以使用外观模式。外观模式可以隐藏系统的复杂性,为客户端提供一个简单的入口点,使得系统的使用更加方便。

需要注意的是,外观模式并不是为了解决子系统的性能问题,而是为了提供一个更好的接口和封装子系统的复杂性。因此,在使用外观模式时,需要权衡封装和灵活性之间的关系,确保。

外观模式的缺点包括:

  1. 违反开闭原则:当新增或修改子系统的功能时,可能需要修改外观类的代码。这违反了开闭原则,因为外观类的变化会影响到客户端。

  2. 增加了系统的复杂性:引入外观模式会增加一个额外的外观类,从而增加了系统的复杂性。如果系统本身已经足够简单,引入外观模式可能会增加不必要的复杂性。

  3. 可能造成性能问题:由于外观模式封装了多个子系统的功能,当某个子系统需要进行性能优化时,可能会受到外观模式的限制。外观模式隐藏了子系统的细节,可能无法直接对子系统进行优化。

总体而言,外观模式在某些情况下可以简化客户端与复杂子系统的交互,提供一个简化的接口。然而,需要注意合理使用外观模式,避免滥用,以免引入不必要的复杂性。在设计时,需要考虑到系统的可扩展性和维护性,权衡封装和灵活性的关系。

11.享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享对象来有效地支持大量细粒度的对象。它通过将对象的状态分为内部状态(Intrinsic State)和外部状态(Extrinsic State),使得多个对象可以共享相同的内部状态,从而节省内存和提高性能。

在享元模式中,有以下几个主要角色:

  1. 享元(Flyweight):它是一个接口或抽象类,定义了享元对象的接口。通过该接口,可以共享内部状态和操作外部状态的方法。

  2. 具体享元(Concrete Flyweight):它实现了享元接口,并实现了内部状态的具体逻辑。具体享元对象可以被共享和重用。

  3. 享元工厂(Flyweight Factory):它负责创建和管理享元对象。它维护了一个享元池(Flyweight Pool),用于存储和管理已创建的享元对象。在需要时,享元工厂会返回已存在的享元对象,或者创建新的享元对象。

  4. 客户端(Client):它使用享元对象,并可以操作外部状态。客户端可以通过享元工厂获取共享的享元对象,然后根据需要设置和操作外部状态。

享元模式的核心思想是将对象的状态分为内部状态和外部状态,将内部状态相同的对象共享使用,从而减少对象的数量和内存占用。通过共享对象,可以提高系统的性能和效率。

下面是一个示例代码,演示了享元模式的实现:

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

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

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

    public 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<>();

    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 Main {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();

        // 获取共享的享元对象
        Flyweight flyweight1 = factory.getFlyweight("shared");
        flyweight1.operation("External State 1");

        // 获取共享的享元对象
        Flyweight flyweight2 = factory.getFlyweight("shared");
        flyweight2.operation("External State 2");

        // 获取新的享元对象
        Flyweight flyweight3 = factory.getFlyweight("unshared
        Certainly! Here's the continuation of the Flyweight Pattern example:


        // 获取新的享元对象
        Flyweight flyweight3 = factory.getFlyweight("unshared");
        flyweight3.operation("External State 3");
    }
}

在上面的示例中,我们创建了一个Flyweight接口来定义享元对象的操作。然后,我们实现了ConcreteFlyweight类作为具体的享元对象,并在其构造函数中传入内部状态。在operation方法中,我们展示了内部状态和外部状态的输出。

接下来,我们创建了FlyweightFactory类作为享元工厂,它负责创建和管理享元对象。在getFlyweight方法中,我们首先检查享元池中是否已存在指定内部状态的享元对象,如果存在则返回该对象,否则创建一个新的享元对象并将其添加到享元池中。

最后,在Main类中,我们通过FlyweightFactory获取共享的享元对象,并调用它们的operation方法来展示内部状态和外部状态的输出。此外,我们还获取了一个新的享元对象,展示了不共享的情况。

通过使用享元模式,我们可以有效地共享内部状态相同的对象,从而减少对象的创建和内存消耗。这在需要大量相似对象时特别有用,并可以提高系统的性能和效率。

12.代理模式(Proxy Pattern)

代理模式(Proxy Pattern)是一种结构型设计模式,旨在为其他对象提供一个代理或者占位符,以控制对这个对象的访问。

代理模式涉及以下几个角色:

  1. 抽象主题(Subject):它是一个接口或者抽象类,定义了真实主题和代理主题的共同接口,这样代理可以通过实现相同的接口来替代真实主题。

  2. 真实主题(Real Subject):它是代理所代表的真实对象,是业务逻辑的实际执行者。

  3. 代理(Proxy):它持有对真实主题的引用,并实现了抽象主题的接口。在需要的情况下,代理可以创建、删除或控制真实主题的访问。

使用代理模式可以实现以下目的:

  1. 远程代理(Remote Proxy):代理在不同的地址空间中代表真实主题,使得客户端可以通过代理访问远程对象。

  2. 虚拟代理(Virtual Proxy):代理在需要时创建真实对象,从而实现按需加载的效果。例如,加载大型图像或者视频时可以使用虚拟代理,先显示一个占位符,然后在需要时加载真实的图像或视频。

  3. 安全代理(Protection Proxy):代理可以控制对真实对象的访问权限,以实现安全性控制。

  4. 智能代理(Smart Proxy):代理可以在真实对象的操作前后添加额外的逻辑,实现日志记录、性能监控、缓存等功能。

下面是一个示例代码,演示了代理模式的实现:

// 抽象主题
interface Subject {
    void request();
}

// 真实主题
class RealSubject implements Subject {
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

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

    public void request() {
        if (realSubject == null) {
            realSubject = new RealSubject();
        }
        System.out.println("Proxy: Pre-processing request.");
        realSubject.request();
        System.out.println("Proxy: Post-processing request.");
    }
}

// 示例使用
public class Main {
    public static void main(String[] args) {
        Proxy proxy = new Proxy();
        proxy.request();
    }
}

在上述示例中,我们定义了一个抽象主题接口Subject,其中包含了一个request方法。然后,我们实现了真实主题RealSubject,它实现了抽象主题接口并提供了实际的业务逻辑。

接下来,我们创建了代理类Proxy,它实现了抽象主题接口,并在其request方法中添加了额外的前后处理逻辑。在第一次调用request方法时,代理创建了真实主题
当然,请继续阅读代理模式的示例代码:

        // 示例使用
        public class Main {
            public static void main(String[] args) {
                Proxy proxy = new Proxy();
                proxy.request();
            }
        }

在上述示例中,我们创建了代理类Proxy的实例,并调用了其request方法。当代理的request方法被调用时,它会在真实主题的request方法执行之前和之后添加额外的逻辑。这样,代理就可以控制对真实主题的访问,并在必要时执行一些预处理和后处理操作。

通过使用代理模式,我们可以实现对真实主题的访问控制和增强功能。代理模式可以提供更灵活和安全的方式来访问对象,同时也可以降低对象之间的耦合度。

需要注意的是,代理模式并不一定要求代理类和真实主题实现相同的接口。代理类可以是真实主题的子类或者与真实主题没有继承关系的独立类,只要它们能提供相同的接口,即可被客户端使用。

行为型模式(Behavioral Patterns):

13.责任链模式(Chain of Responsibility Pattern)

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,旨在通过为请求创建一个接收者链,将请求发送给链上的各个接收者,直到有一个接收者能够处理该请求为止。

责任链模式涉及以下几个角色:

  1. 抽象处理者(Handler):它定义了处理请求的接口,并且可以包含一个指向下一个处理者的引用。它通常是一个抽象类或者接口。

  2. 具体处理者(Concrete Handler):它实现了抽象处理者的接口,负责处理请求。如果它能够处理请求,则处理请求;否则,将请求传递给下一个处理者。

使用责任链模式可以将请求的发送者和接收者解耦,并且可以灵活地组织处理者的链。当有多个对象可以处理同一请求时,可以使用责任链模式来动态确定请求的处理者。

下面是一个示例代码,演示了责任链模式的实现:

// 抽象处理者
abstract class Handler {
    private Handler nextHandler;

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

    public void handleRequest(Request request) {
        if (canHandle(request)) {
            processRequest(request);
        } else if (nextHandler != null) {
            nextHandler.handleRequest(request);
        } else {
            System.out.println("No handler available for the request.");
        }
    }

    protected abstract boolean canHandle(Request request);

    protected abstract void processRequest(Request request);
}

// 具体处理者A
class ConcreteHandlerA extends Handler {
    protected boolean canHandle(Request request) {
        // 判断是否能够处理该请求
        // 如果可以处理,则返回true;否则返回false
    }

    protected void processRequest(Request request) {
        // 处理请求的逻辑
    }
}

// 具体处理者B
class ConcreteHandlerB extends Handler {
    protected boolean canHandle(Request request) {
        // 判断是否能够处理该请求
        // 如果可以处理,则返回true;否则返回false
    }

    protected void processRequest(Request request) {
        // 处理请求的逻辑
    }
}

// 请求类
class Request {
    // 请求的数据和信息
}

// 示例使用
public class Main {
    public static void main(String[] args) {
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();

        handlerA.setNextHandler(handlerB);

        Request request = new Request();
        handlerA.handleRequest(request);
    }
}

在上述示例中,我们定义了一个抽象处理者类Handler,其中包含一个指向下一个处理者的引用nextHandler。它定义了handleRequest方法,用于处理请求。如果当前处理者能够处理请求,则处理请求;否则,将请求传递给下一个处理者。

然后,我们创建了具体处理者类ConcreteHandlerAConcreteHandlerB,它们分别实现了抽象处理者类的抽象方法canHandleprocessRequest。在这些方法中,我们可以继续上述示例:

在具体处理者类中,我们根据具体业务逻辑实现了canHandle方法和processRequest方法。canHandle方法用于判断当前处理者是否能够处理请求,如果能够处理,则返回true;否则返回false。processRequest方法用于处理请求的具体逻辑。

在示例的Main类中,我们创建了具体处理者对象handlerAhandlerB,并将它们通过setNextHandler方法构建成一个处理者链。然后,我们创建了一个请求对象request,并调用handleRequest方法将请求发送给处理者链的第一个处理者handlerA

处理者链会按照顺序逐个尝试处理请求,如果某个处理者能够处理请求,则会停止传递给下一个处理者;如果所有处理者都不能处理请求,则会输出相应的提示信息。

通过使用责任链模式,我们可以动态地组织和调整处理者链,实现灵活的请求处理。这种模式可以降低发送者和接收者之间的耦合度,并且可以避免请求发送者需要明确知道每个接收者的情况。

14. 命令模式(Command Pattern)

命令模式(Command Pattern)是一种行为型设计模式,旨在将请求封装成对象,从而使得可以用不同的请求对客户端进行参数化,并且能够将请求排队或者记录请求日志,以及支持可撤销的操作。

命令模式涉及以下几个角色:

  1. 命令接口(Command):它定义了执行请求的方法。通常包含一个execute方法。

  2. 具体命令(Concrete Command):它实现了命令接口,具体定义了执行请求的逻辑,并持有一个接收者对象的引用。通常包含一个构造函数用于接收接收者对象的引用,并在execute方法中调用接收者的相关方法来执行请求。

  3. 接收者(Receiver):它负责实际执行请求的对象。命令模式将请求发送给接收者来执行具体的操作。

  4. 调用者(Invoker):它持有命令对象,并在需要的时候调用命令对象的execute方法来执行请求。

使用命令模式可以将请求发送者与接收者解耦,使得发送者只需知道如何发送请求,而无需关心请求的具体执行逻辑。同时,可以很容易地扩展命令对象,实现新的请求操作,而无需修改已有的发送者和接收者。

下面是一个示例代码,演示了命令模式的实现:

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

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

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

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

// 接收者
class Receiver {
    public void action() {
        System.out.println("Receiver: Performing action.");
    }
}

// 调用者
class Invoker {
    private Command command;

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

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

// 示例使用
public class Main {
    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,它实现了命令接口,并在其构造函数中接收一个接收者对象的引用。在execute方法中,我们调用接收者的action方法来执行请求。

接下来,我们创建了接收者类Receiver,它负责实际执行请求的操作。

然后,我们创建了调用者类Invoker,它持有一个命令对象,并提供了setCommandexecuteCommand方法。setCommand方法继续上述示例:

setCommand方法用于设置具体的命令对象,而executeCommand方法则调用命令对象的execute方法来执行请求。

在示例的Main类中,我们创建了接收者对象receiver、具体命令对象command和调用者对象invoker。首先,我们将具体命令对象设置到调用者对象中,然后调用executeCommand方法来执行命令。

通过使用命令模式,我们将请求封装成了命令对象,实现了请求发送者和请求接收者之间的解耦。发送者只需通过调用者对象来执行请求,而无需知道具体的执行逻辑。

此外,命令模式还支持撤销操作。我们可以在命令对象中添加撤销方法,并在需要撤销时调用撤销方法即可恢复原来的状态。

15. 解释器模式(Interpreter Pattern)

解释器模式(Interpreter Pattern)是一种行为型设计模式,用于解决特定问题领域中的语言解释和表达式求值问题。它定义了一个语言的文法,并通过解释器来解释和执行语言中的表达式。

解释器模式涉及以下几个角色:

  1. 抽象表达式(Abstract Expression):它定义了解释器的接口,声明了一个interpret方法,用于解释表达式。

  2. 终结符表达式(Terminal Expression):它实现了抽象表达式接口,并表示语言中的终结符(最小的语法单位)。终结符表达式无需进行解释,其interpret方法通常直接返回结果。

  3. 非终结符表达式(Non-terminal Expression):它实现了抽象表达式接口,并表示语言中的非终结符。非终结符表达式通常由多个终结符表达式和其他非终结符表达式组合而成,通过递归调用自身的interpret方法来解释表达式。

  4. 上下文(Context):它包含了待解释的语言表达式。

使用解释器模式可以实现复杂语言的解析和执行。每个表达式对应一个解释器,解释器根据文法规则对表达式进行解释。通过解释器模式,我们可以将复杂的语言解析问题拆解成一系列简单的表达式解释。

下面是一个示例代码,演示了解释器模式的实现:

// 抽象表达式
interface Expression {
    int interpret(Context context);
}

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

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

    public int interpret(Context context) {
        return context.getValue(data);
    }
}

// 非终结符表达式
class NonterminalExpression implements Expression {
    private Expression expression1;
    private Expression expression2;

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

    public int interpret(Context context) {
        // 对expression1和expression2进行解释操作
        // 返回解释后的结果
    }
}

// 上下文
class Context {
    private Map<String, Integer> variables;

    public Context() {
        variables = new HashMap<>();
    }

    public void setValue(String variable, int value) {
        variables.put(variable, value);
    }

    public int getValue(String variable) {
        return variables.get(variable);
    }
}

// 示例使用
public class Main {
    public static void main(String[] args) {
        Context context = new Context();
        context.setValue("x", 5);
        context.setValue("y", 10);

        Expression expression = new NonterminalExpression(
                new TerminalExpression("x"),
                new TerminalExpression("y")
        );

        int result = expression.interpret(context);
        System.out.println("Result: " + result);
    }
}

在上述示例中,我们定义继续上述示例:

我们定义了一个抽象表达式接口Expression,其中包含了一个interpret方法。终结符表达式TerminalExpression和非终结符表达式NonterminalExpression分别实现了抽象表达式接口,并提供了具体的解释逻辑。

上下文类Context包含了待解释的语言表达式,并提供了变量值的存储和获取方法。

在示例的Main类中,我们创建了上下文对象context,并为变量"x"和"y"设置了具体的值。然后,我们创建了一个非终结符表达式对象expression,其中包含了两个终结符表达式对象"x"和"y"。最后,我们调用interpret方法对表达式进行解释,并输出结果。

通过使用解释器模式,我们可以灵活地定义和解释复杂的语言表达式,从而实现语言的解析和执行。解释器模式在编译器设计、规则引擎、正则表达式等领域有广泛的应用。

16. 迭代器模式(Iterator Pattern)

迭代器模式(Iterator Pattern)是一种行为型设计模式,用于提供一种统一的方式来遍历集合对象(如列表、数组等)的元素,而无需暴露集合对象的内部表示。

迭代器模式涉及以下几个角色:

  1. 迭代器接口(Iterator):它定义了遍历集合对象元素的方法,如获取下一个元素、判断是否还有下一个元素等。

  2. 具体迭代器(Concrete Iterator):它实现了迭代器接口,并负责实际遍历集合对象的元素。

  3. 集合接口(Aggregate):它定义了创建迭代器对象的方法。

  4. 具体集合(Concrete Aggregate):它实现了集合接口,并返回一个具体迭代器对象。

使用迭代器模式,我们可以封装集合对象的遍历逻辑,使得遍历过程与集合对象分离,从而可以独立地进行遍历操作。

下面是一个示例代码,演示了迭代器模式的实现:

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

// 集合接口
interface Aggregate<T> {
    Iterator<T> createIterator();
}

// 具体迭代器
class ConcreteIterator<T> implements Iterator<T> {
    private T[] elements;
    private int position;

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

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

    public T next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }
        return elements[position++];
    }
}

// 具体集合
class ConcreteAggregate<T> implements Aggregate<T> {
    private T[] elements;

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

    public Iterator<T> createIterator() {
        return new ConcreteIterator<T>(elements);
    }
}

// 示例使用
public class Main {
    public static void main(String[] args) {
        Integer[] numbers = {1, 2, 3, 4, 5};
        Aggregate<Integer> aggregate = new ConcreteAggregate<Integer>(numbers);
        Iterator<Integer> iterator = aggregate.createIterator();

        while (iterator.hasNext()) {
            Integer number = iterator.next();
            System.out.println(number);
        }
    }
}

在上述示例中,我们定义了迭代器接口Iterator,其中包含了hasNextnext方法,用于判断是否还有下一个元素和获取下一个元素。

集合接口Aggregate定义了一个createIterator方法,用于创建迭代器对象。

具体迭代器ConcreteIterator实现了迭代器接口,通过数组来遍历集合对象的元素。

具体集合ConcreteAggregate实现了集合接口,返回一个具体迭代器对象。

在示例的Main类中,我们创建了一个整数数组numbers作为集合对象,并通过具体集合ConcreteAggregate创建了一个迭代继续上述示例:

器对象iterator。然后,我们使用迭代器对象遍历集合中的元素,并输出每个元素的值。

通过使用迭代器模式,我们可以通过统一的接口遍历不同类型的集合对象,而无需关心其具体的内部实现方式。这提供了一种灵活的方式来遍历集合,并使得集合对象与遍历算法解耦。

迭代器模式在许多编程环境和框架中都得到广泛应用,例如在Java的集合框架中,Iterator接口和Iterable接口就是迭代器模式的实现。

17. 中介者模式(Mediator Pattern)

中介者模式(Mediator Pattern)是一种行为型设计模式,用于减少对象之间的直接耦合,并促进对象之间的松散通信。中介者模式通过引入一个中介者对象,将对象间的交互行为封装在中介者对象中,从而实现对象间的解耦。

在中介者模式中,存在以下几个角色:

  1. 中介者(Mediator):它定义了一个接口,用于定义对象之间的通信方法。

  2. 具体中介者(Concrete Mediator):它实现了中介者接口,并负责协调和管理对象之间的通信。具体中介者了解各个对象之间的关系和行为,根据接收到的请求进行相应的处理和转发。

  3. 同事类(Colleague):它定义了一个接口,用于与其他同事对象进行通信。

  4. 具体同事类(Concrete Colleague):它实现了同事接口,并与其他同事对象进行通信。在具体同事类中,如果需要与其他同事对象通信,则将请求转发给中介者对象。

中介者模式通过将对象之间的通信集中在中介者对象中,避免了对象之间的直接耦合,从而提高了系统的可维护性和灵活性。当系统中对象之间的交互关系复杂且需要进行灵活调整时,中介者模式能够有效地简化对象之间的通信过程。

以下是一个示例代码,演示了中介者模式的实现:

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

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

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

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

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

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

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

    public abstract void send(String message);
    public abstract void receive(String message);
}

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

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

    public void receive(String message) {
        System.out.println("ConcreteColleague1 received: " + message);
    }
}

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

    public void send(String message) {
        mediator.send(message, this);
    }
    public void receive(String message) {
        System.out.println("ConcreteColleague2 received: " + message);
    }
}

// 示例使用
public class Main {
    public static void main(String[] args) {
        ConcreteMediator mediator = new ConcreteMediator();

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

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

        colleague1.send("Hello from ConcreteColleague1!");
        colleague2.send("Hi from ConcreteColleague2!");
    }
}

在上述示例中,我们定义了中介者接口Mediator,其中包含了一个send方法用于同事对象之间的通信。

具体中介者ConcreteMediator实现了中介者接口,并实现了根据不同的同事对象进行消息转发的逻辑。

同事类Colleague定义了抽象方法send和receive,用于发送和接收消息。

具体同事类ConcreteColleague1和ConcreteColleague2分别实现了同事类,并在发送消息时调用中介者的send方法进行消息的转发。

在示例的Main类中,我们创建了一个具体中介者对象mediator,以及两个具体同事对象colleague1和colleague2。然后,我们将同事对象注册到中介者中,并通过调用同事对象的send方法发送消息。

通过中介者模式,同事对象之间不再直接耦合,而是通过中介者进行通信,从而实现了对象之间的解耦。这样可以使得系统更加灵活和可维护。

18. 备忘录模式(Memento Pattern)

备忘录模式(Memento Pattern)是一种行为型设计模式,用于捕获对象的内部状态,并在需要时恢复该状态。备忘录模式提供了一种方式,使得对象可以保存其内部状态的快照,而不会破坏封装性。

在备忘录模式中,存在以下几个角色:

  1. 发起人(Originator):它是需要保存和恢复状态的对象。发起人可以创建一个备忘录对象,用于保存其当前状态,并可以从备忘录中恢复之前的状态。

  2. 备忘录(Memento):它是用于存储发起人对象的内部状态的对象。备忘录可以包含发起人对象的状态信息,并提供给发起人对象进行状态恢复。

  3. 管理者(Caretaker):它负责管理备忘录对象,并确保备忘录的安全存储和恢复。管理者可以存储多个备忘录对象,并根据需要进行状态恢复。

备忘录模式通过将对象的状态保存到备忘录对象中,实现了状态的保存和恢复,同时保持了对象的封装性。这样,对象可以在不暴露其内部结构的情况下进行状态的保存和恢复。

以下是一个示例代码,演示了备忘录模式的实现:

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

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

    public String getState() {
        return state;
    }
}

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

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

    public String getState() {
        return state;
    }

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

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

// 管理者类
class Caretaker {
    private List<Memento> mementos = new ArrayList<>();

    public void addMemento(Memento memento) {
        mementos.add(memento);
    }

    public Memento getMemento(int index) {
        return mementos.get(index);
    }
}

// 示例使用
public class Main {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        // 设置发起人的初始状态
        originator.setState("State 1");

        // 保存初始状态到备忘录
        caretaker.addMemento(originator.createMemento());

        // 修改发起人的状态
        originator.setState("State 2");

        // 保存修改后的状态到备忘录
        caretaker.addMemento(originator.createMemento());

        // 恢复到初始状态
        originator.restoreMemento(caretaker.getMemento(0));

        System.out.println(originator.getState());  // 输出: State 1
    }
}

class Memento {
    private String state;

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

    public String getState() {
        return state;
    }
}

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

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

    public String getState() {
        return state;
    }

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

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

// 管理者类
class Caretaker {
    private List<Memento> mementos = new ArrayList<>();

    public void addMemento(Memento memento) {
        mementos.add(memento);
    }

    public Memento getMemento(int index) {
        return mementos.get(index);
    }
}

// 示例使用
public class Main {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        // 设置发起人的初始状态
        originator.setState("State 1");

        // 保存初始状态到备忘录
        caretaker.addMemento(originator.createMemento());

        // 修改发起人的状态
        originator.setState("State 2");

        // 保存修改后的状态到备忘录
        caretaker.addMemento(originator.createMemento());

        // 恢复到初始状态
        originator.restoreMemento(caretaker.getMemento(0));

        System.out.println(originator.getState());  // 输出: State 1
    }
}

在示例中,我们创建了一个发起人对象Originator,它具有一个状态属性state和相应的设置和获取方法。发起人对象可以创建备忘录对象Memento,其中保存了当前的状态。

我们还创建了一个管理者对象Caretaker,它负责管理备忘录对象。管理者可以保存多个备忘录对象,并提供获取备忘录的方法。

在示例的Main类中,我们创建了发起人对象和管理者对象,并进行了如下操作:

  1. 设置发起人对象的初始状态为"State 1",并将其保存到备忘录对象中。

  2. 修改发起人对象的状态为"State 2",并将其保存到备忘录对象中。

  3. 通过管理者对象获取之前保存的备忘录对象,并调用发起人对象的恢复方法,将状态恢复到初始状态。

最终,我们输出发起人对象的状态,可以看到恢复操作成功,状态变为了"State 1"。

备忘录模式可以用于需要保存和恢复对象状态的场景,例如撤销操作、系统恢复等。它通过将状态保存到备忘录对象中,使得对象的状态可以在需要时进行恢复,同时保持了对象的封装性。

19. 观察者模式(Observer Pattern)

观察者模式(Observer Pattern)是一种行为型设计模式,用于定义对象之间的一对多依赖关系,使得当一个对象状态发生改变时,所有依赖于它的对象都能够得到通知并自动更新。

在观察者模式中,存在以下几个角色:

  1. 主题(Subject):也称为被观察者或可观察对象,它维护了一组观察者对象,并提供了添加、删除和通知观察者的方法。主题对象状态的改变会触发通知操作,通知所有观察者进行更新。

  2. 观察者(Observer):观察者对象依赖于主题对象,并通过注册自己到主题对象上,以接收主题对象的通知。当主题对象状态发生改变时,观察者对象会被通知,并执行相应的更新操作。

观察者模式通过解耦主题对象和观察者对象,实现了对象之间的松耦合关系。当主题对象的状态发生改变时,无需知道具体的观察者对象,只需通知观察者对象进行更新。这样,主题对象和观察者对象之间的依赖关系更加灵活,可扩展性更高。

以下是一个示例代码,演示了观察者模式的实现:

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

// 主题接口
interface Subject {
    void addObserver(Observer observer);

    void removeObserver(Observer observer);

    void notifyObservers();
}

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

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

    public int getState() {
        return state;
    }

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(this);
        }
    }
}

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

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

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

    @Override
    public void update(Subject subject) {
        System.out.println("Observer " + name + " is notified. New state: " + ((ConcreteSubject) subject).getState());
    }
}

// 示例使用
public class Main {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();

        ConcreteObserver observer1 = new ConcreteObserver("Observer 1");
        ConcreteObserver observer2 = new ConcreteObserver("Observer 2");

        subject.addObserver(observer1);
        subject.addObserver(observer2);

        subject.setState(1);
        subject.setState(2);
        subject.setState(3);

        subject.removeObserver(observer2);

        subject.setState(4);
    }
}

在上述示例中,我们定义了一个主题接口Subject和一个具体主题类ConcreteSubject,以及一个观察者接口Observer和一个具体观察者类ConcreteObserver

ConcreteSubject类中,我们维护了一个观察者列表observers,并实现了主题接口的方法。具体来说,addObserver方法用于向观察者列表中添加观察者,removeObserver方法用于从观察者列表中移除观察者,notifyObservers方法用于通知所有观察者进行更新。当ConcreteSubject对象的状态发生改变时,我们调用notifyObservers方法通知所有观察者进行更新。

ConcreteObserver类中,我们实现了观察者接口的方法update,当观察者接收到主题对象的通知时,它会执行相应的更新操作。在示例中,更新操作包括打印观察者的名称和主题对象的新状态。

Main类中,我们创建了一个具体主题对象subject,以及两个具体观察者对象observer1observer2。我们通过调用addObserver方法将观察者注册到主题对象上。然后,我们通过调用setState方法改变主题对象的状态,从而触发通知操作,观察者会接收到通知并执行相应的更新操作。最后,我们通过调用removeObserver方法将一个观察者从主题对象中移除,再次调用setState方法不会再通知被移除的观察者。

执行以上代码,输出如下结果:

Observer Observer 1 is notified. New state: 1
Observer Observer 2 is notified. New state: 1
Observer Observer 1 is notified. New state: 2
Observer Observer 2 is notified. New state: 2
Observer Observer 1 is notified. New state: 3
Observer Observer 2 is notified. New state: 3
Observer Observer 1 is notified. New state: 4

可以看到,当主题对象的状态发生改变时,观察者对象会得到通知并进行更新。

观察者模式适用于以下情况:

  • 当一个对象的改变需要同时通知其他多个对象,并且这些对象之间存在松耦合关系时。
  • 当一个对象需要通知其他对象,但不希望与其形成紧耦合关系。

通过使用观察者模式,可以实现对象之间的解耦,提高系统的灵活性和可扩展性。

20. 状态模式(State Pattern)

状态模式(State Pattern)是一种行为型设计模式,它允许对象在内部状态发生变化时改变其行为。状态模式将对象的状态封装成独立的类,并将对象的行为委托给当前状态类。

在状态模式中,存在以下几个角色:

  1. 环境(Context):它定义了客户端所感兴趣的接口,维护一个当前状态对象,并将客户端的请求委托给当前状态处理。

  2. 抽象状态(State):它是状态的抽象基类或接口,定义了状态的方法,用于处理环境的请求,并可以在需要时切换到其他状态。

  3. 具体状态(Concrete State):它是抽象状态的子类,实现了具体的状态行为。在具体状态中处理环境的请求,可能会导致环境的状态转移。

状态模式通过将状态的行为封装到具体的状态类中,实现了状态与行为的解耦。当环境的状态发生改变时,它会委托给当前状态对象处理请求,并且可以在运行时动态地改变状态,从而改变对象的行为。

以下是一个示例代码,演示了状态模式的实现:

// 抽象状态类
abstract class State {
    protected Context context;

    public void setContext(Context context) {
        this.context = context;
    }

    public abstract void handle();
}

// 具体状态类 A
class ConcreteStateA extends State {
    @Override
    public void handle() {
        System.out.println("Handling in State A");
        // 状态转移
        context.setState(new ConcreteStateB());
    }
}

// 具体状态类 B
class ConcreteStateB extends State {
    @Override
    public void handle() {
        System.out.println("Handling in State B");
        // 状态转移
        context.setState(new ConcreteStateA());
    }
}

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

    public Context() {
        // 初始状态为 A
        currentState = new ConcreteStateA();
        currentState.setContext(this);
    }

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

    public void request() {
        currentState.handle();
    }
}

// 示例使用
public class Main {
    public static void main(String[] args) {
        Context context = new Context();

        // 连续执行两次请求
        context.request();
        context.request();
    }
}

在上述示例中,我们定义了一个抽象状态类State,并派生出两个具体状态类ConcreteStateAConcreteStateB。在抽象状态类中,我们定义了一个环境对象的引用,并提供了抽象的处理方法handle

在环境类Context中,我们维护了当前状态对象currentState,并在初始化时将其设置为初始状态ConcreteStateA。通过调用setState方法,可以在运行时动态地改变当前状态。在请求方法request中,我们通过调用当前状态对象的handle方法来处理请求。

在示例中,初始状态为ConcreteStateA。当调用context.request()时,当前状态为ConcreteStateA,因此会执行ConcreteStateAhandle方法,并输出"Handling in State A"。在ConcreteStateAhandle方法中,我们进行了状态转移,将当前状态设置为ConcreteStateB。再次调用context.request()时,当前状态为ConcreteStateB,会执行ConcreteStateBhandle方法,并输出"Handling in State B"。在ConcreteStateBhandle方法中,又进行了状态转移,将当前状态设置为ConcreteStateA

执行以上代码,输出如下结果:

Handling in State A
Handling in State B

可以看到,随着状态的改变,环境对象的行为也随之改变。

状态模式适用于以下情况:

  • 当一个对象的行为取决于其内部状态,并且在运行时需要根据状态的改变而改变行为时。
  • 当有多个具体状态类存在,并且需要将状态转移的逻辑封装在具体状态类中,以避免状态切换逻辑在环境类中的复杂性。

通过使用状态模式,可以实现对象状态与行为之间的解耦,提高代码的可维护性和扩展性。

21. 策略模式(Strategy Pattern)

策略模式(Strategy Pattern)是一种行为型设计模式,它允许在运行时选择算法的行为。该模式将不同的算法封装成独立的策略类,使得它们可以相互替换,而不影响客户端的使用。

在策略模式中,存在以下几个角色:

  1. 环境(Context):它定义了客户端所感兴趣的接口,维护一个对策略对象的引用,并将具体的请求委托给策略对象进行处理。

  2. 抽象策略(Strategy):它是策略的抽象基类或接口,定义了策略的方法。

  3. 具体策略(Concrete Strategy):它是抽象策略的子类,实现了具体的算法逻辑。

策略模式通过将算法的实现封装到具体的策略类中,使得算法的选择和使用可以独立于客户端进行变化。客户端只需要与抽象策略进行交互,而不需要直接依赖于具体的策略类。

以下是一个示例代码,演示了策略模式的实现:

// 抽象策略类
interface Strategy {
    void execute();
}

// 具体策略类 A
class ConcreteStrategyA implements Strategy {
    @Override
    public void execute() {
        System.out.println("Executing strategy A");
    }
}

// 具体策略类 B
class ConcreteStrategyB implements Strategy {
    @Override
    public void execute() {
        System.out.println("Executing strategy B");
    }
}

// 环境类
class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

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

// 示例使用
public class Main {
    public static void main(String[] args) {
        Strategy strategyA = new ConcreteStrategyA();
        Context contextA = new Context(strategyA);
        contextA.executeStrategy();

        Strategy strategyB = new ConcreteStrategyB();
        Context contextB = new Context(strategyB);
        contextB.executeStrategy();
    }
}

在上述示例中,我们定义了一个抽象策略类Strategy,并派生出两个具体策略类ConcreteStrategyAConcreteStrategyB。在抽象策略类中,我们定义了策略的方法execute

在环境类Context中,我们维护了一个策略对象strategy,并通过构造函数进行注入。在executeStrategy方法中,我们调用策略对象的execute方法来执行具体的算法逻辑。

在示例中,我们创建了两个具体策略对象strategyAstrategyB,并分别传递给不同的环境对象contextAcontextB。通过调用`executeStrategy方法,可以根据需要执行不同的策略。

执行以上代码,输出如下结果:

Executing strategy A
Executing strategy B

可以看到,根据传入的不同策略,环境对象执行了不同的算法。

策略模式适用于以下情况:

  • 当需要在运行时根据不同的情况选择不同的算法或行为时。
  • 当有多个相关的类,它们的行为仅在某些情况下略有不同,可以通过策略模式将这些变化封装到独立的策略类中,避免使用大量的条件语句。

通过使用策略模式,可以使算法的变化独立于使用算法的客户端,提高代码的灵活性和可维护性。

22. 模板方法模式(Template Method Pattern)

模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个操作中的算法的骨架,将一些步骤延迟到子类中实现。模板方法模式使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

在模板方法模式中,存在以下几个角色:

  1. 抽象类(Abstract Class):它定义了一个模板方法,其中包含了算法的骨架,而某些步骤的具体实现由子类来完成。

  2. 具体类(Concrete Class):它是抽象类的子类,实现了具体步骤的具体实现。

模板方法模式通过将算法的骨架定义在抽象类中,将某些具体步骤的实现留给子类去完成。这样可以确保算法的结构不变,但允许不同的子类提供不同的实现细节。

以下是一个示例代码,演示了模板方法模式的实现:

// 抽象类
abstract class AbstractClass {
    public void templateMethod() {
        step1();
        step2();
        step3();
    }

    protected abstract void step1();

    protected abstract void step2();

    protected abstract void step3();
}

// 具体类 A
class ConcreteClassA extends AbstractClass {
    @Override
    protected void step1() {
        System.out.println("ConcreteClassA: Step 1");
    }

    @Override
    protected void step2() {
        System.out.println("ConcreteClassA: Step 2");
    }

    @Override
    protected void step3() {
        System.out.println("ConcreteClassA: Step 3");
    }
}

// 具体类 B
class ConcreteClassB extends AbstractClass {
    @Override
    protected void step1() {
        System.out.println("ConcreteClassB: Step 1");
    }

    @Override
    protected void step2() {
        System.out.println("ConcreteClassB: Step 2");
    }

    @Override
    protected void step3() {
        System.out.println("ConcreteClassB: Step 3");
    }
}

// 示例使用
public class Main {
    public static void main(String[] args) {
        AbstractClass classA = new ConcreteClassA();
        classA.templateMethod();

        AbstractClass classB = new ConcreteClassB();
        classB.templateMethod();
    }
}

在上述示例中,我们定义了一个抽象类AbstractClass,其中包含了一个模板方法templateMethod,该方法定义了算法的骨架。同时,我们也定义了三个抽象方法step1step2step3,这些方法由子类来实现具体的步骤。

我们派生出两个具体类ConcreteClassAConcreteClassB,它们分别实现了抽象类中的抽象方法。通过调用templateMethod方法,我们可以执行算法的骨架,并由具体类提供实际的步骤实现。

执行以上代码,输出如下结果:

ConcreteClassA: Step 1
ConcreteClassA: Step 2
ConcreteClassA: Step 3
ConcreteClassB: Step 1
ConcreteClassB: Step 2
ConcreteClassB: Step 3

可以看到,通过调用模板方法templateMethod,算法的骨架被执行,其中的具体步骤由具体类提供实现。

模板方法模式适用于以下情况:

  • 当有一个算法的骨架,但其中某些步骤的具体实现可能有所不同时。
  • 当需要在不改变算法结构的情况下,允许子类定制算法中的某些步骤时。

通过使用模板方法模式,可以将算法的通用部分封装在抽象类中,提高代码的重用性和可维护性。同时,它也使得算法的具体实现能够在子类中进行灵活的定制。

23. 访问者模式(Visitor Pattern)

访问者模式(Visitor Pattern)是一种行为型设计模式,它允许在不改变被访问元素的类的前提下,定义新的操作(访问者)并应用于这些元素上。

访问者模式的核心思想是将数据结构和操作分离,使得可以在不修改数据结构的情况下,添加新的操作。

在访问者模式中,存在以下几个角色:

  1. 抽象访问者(Visitor):它定义了访问者的接口,声明了可以访问各种元素的方法。

  2. 具体访问者(Concrete Visitor):它实现了抽象访问者定义的接口,实现了对元素的具体访问操作。

  3. 抽象元素(Element):它定义了元素的接口,声明了接受访问者访问的方法。

  4. 具体元素(Concrete Element):它实现了抽象元素定义的接口,实现了接受访问者访问的方法。

  5. 对象结构(Object Structure):它是元素的集合,提供了遍历元素的方法。

访问者模式通过在元素类中定义接受访问者访问的方法,并在访问者类中定义对元素的具体访问操作,使得新的操作可以被添加到系统中,同时也遵循了开闭原则。

以下是一个示例代码,演示了访问者模式的实现:

// 抽象访问者
interface Visitor {
    void visit(ElementA element);
    void visit(ElementB element);
}

// 具体访问者 A
class ConcreteVisitorA implements Visitor {
    @Override
    public void visit(ElementA element) {
        System.out.println("Visitor A visits Element A");
    }

    @Override
    public void visit(ElementB element) {
        System.out.println("Visitor A visits Element B");
    }
}

// 具体访问者 B
class ConcreteVisitorB implements Visitor {
    @Override
    public void visit(ElementA element) {
        System.out.println("Visitor B visits Element A");
    }

    @Override
    public void visit(ElementB element) {
        System.out.println("Visitor B visits Element B");
    }
}

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

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

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

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

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

    public void removeElement(Element element) {
        elements.remove(element);
    }

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

// 示例使用
public class Main {
    public static void main(String[] args) {
        Visitor
Visitor visitorA = new ConcreteVisitorA();
        Visitor visitorB = new ConcreteVisitorB();

        Element elementA = new ElementA();
        Element elementB = new ElementB();

        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.addElement(elementA);
        objectStructure.addElement(elementB);

        objectStructure.accept(visitorA);
        objectStructure.accept(visitorB);
    }
}

在上述示例中,我们定义了抽象访问者Visitor和具体访问者ConcreteVisitorAConcreteVisitorB,它们实现了对元素的具体访问操作。

我们还定义了抽象元素Element和具体元素ElementAElementB,其中元素类中定义了接受访问者访问的方法accept

最后,我们定义了对象结构ObjectStructure,它包含了一组元素,并提供了遍历元素的方法。

在示例中,我们创建了两个具体访问者visitorAvisitorB,以及两个具体元素elementAelementB。然后,我们将这些元素添加到对象结构中,并通过调用accept方法来接受访问者的访问。

执行以上代码,输出如下结果:

Visitor A visits Element A
Visitor A visits Element B
Visitor B visits Element A
Visitor B visits Element B

可以看到,不同的访问者对元素进行了不同的访问操作。

访问者模式适用于以下情况:

  • 当需要在不改变元素类的情况下,定义新的操作并应用于元素时。
  • 当有多个不相关的操作需要在元素集合上执行时。
  • 当元素的结构比其操作算法更稳定,且希望通过增加新的操作来扩展系统时。

通过使用访问者模式,可以实现元素和操作之间的解耦,使得操作可以独立于元素的结构变化而变化。同时,也易于添加新的操作而不影响现有的元素类。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值