设计模式

目录

策略模式

策略模式是一种行为设计模式,它允许在运行时选择算法的行为。它通过封装一组算法并将其相互替换来实现这一点。策略模式使得算法可独立于使用它们的客户端而变化,从而提高了代码的灵活性和可维护性。

策略模式的核心思想是将不同的算法封装为一个对象,并且这些对象之间可以互相替换。通常情况下,我们会定义一个接口或抽象类来表示算法的行为,并由具体的算法类去实现这个接口或继承这个抽象类,然后在客户端通过创建这些具体的算法对象并将其传递给其他对象来实现某些操作。

适用场景

  • 当需要在不同情况下使用不同的算法时,例如排序、搜索等。
  • 当需要避免条件语句重复出现时,例如大量if语句。
  • 当需要增强代码的可扩展性和可维护性时,例如添加新的算法。

策略模式通常用于以下场景:

  • 消息处理器:根据不同的消息类型执行不同的处理算法。
  • 数据库连接器:根据不同的数据库类型执行不同的数据库连接算法。
  • 订单处理器:根据不同的订单类型执行不同的订单处理算法。

代码示例

// 定义策略接口
interface Strategy {
  public int doOperation(int num1, int num2);
}

// 实现策略接口的具体策略类
class OperationAdd implements Strategy {
  public int doOperation(int num1, int num2) {
    return num1 + num2;
  }
}

class OperationSubtract implements Strategy {
  public int doOperation(int num1, int num2) {
    return num1 - num2;
  }
}

class OperationMultiply implements Strategy {
  public int doOperation(int num1, int num2) {
    return num1 * num2;
  }
}

// 定义策略模式的上下文
class Context {
  private Strategy strategy;

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

  public int executeStrategy(int num1, int num2){
    return strategy.doOperation(num1, num2);
  }
}

// 使用策略模式的客户端
public class StrategyPatternDemo {
  public static void main(String[] args) {
    Context context = new Context(new OperationAdd());    
    System.out.println("10 + 5 = " + context.executeStrategy(10, 5));

    context = new Context(new OperationSubtract());      
    System.out.println("10 - 5 = " + context.executeStrategy(10, 5));

    context = new Context(new OperationMultiply());    
    System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
  }
}

工厂模式

工厂模式是一种创建型设计模式,它提供了一种将对象的创建过程封装起来的方法。在工厂模式中,我们通过定义一个抽象工厂接口或者抽象类来表示对象的创建过程,然后由具体的工厂类去实现这个接口或继承这个抽象类,并负责具体的对象创建。客户端只需要知道这个抽象工厂即可,不需要关心具体的实现。

适用场景

  • 当我们需要根据不同的条件来创建不同类型的对象时,例如数据库连接器等。
  • 当我们需要隐藏对象的实例化过程时,例如单例模式。
  • 当我们需要优化系统性能时,避免重复的创建对象过程。

工厂模式通常用于以下场景:

  • 数据库连接器:根据不同的数据库类型创建不同的数据库连接器。
  • 图像处理器:根据不同的图像格式创建不同的图像处理器。
  • 日志记录器:创建不同的日志记录器,例如文件日志记录器、数据库日志记录器等。

总之,当需要动态地创建不同类型的对象时,且客户端不需要关心对象的创建过程和细节时,可以使用工厂模式。

代码示例

// 定义一个接口
interface Product {
  void operation();
}

// 实现接口的具体类
class ConcreteProductA implements Product {
  @Override
  public void operation() {
    System.out.println("ConcreteProductA operation");
  }
}

class ConcreteProductB implements Product {
  @Override
  public void operation() {
    System.out.println("ConcreteProductB operation");
  }
}

// 工厂类
class Factory {
  public static Product createProduct(String type) {
    if (type.equals("A")) {
      return new ConcreteProductA();
    } else if (type.equals("B")) {
      return new ConcreteProductB();
    } else {
      return null;
    }
  }
}

// 使用工厂类创建对象
public class Main {
  public static void main(String[] args) {
    Product productA = Factory.createProduct("A");
    productA.operation();

    Product productB = Factory.createProduct("B");
    productB.operation();
  }
}

适配者模式

适配器模式是一种结构型设计模式,它允许将一个类的接口转换为客户端所期望的另一个接口。适配器模式通常用于将一些现有的类与其他类集成在一起,以实现新的功能或者适应新的系统环境。

适配器模式中包含三个角色:

  • 目标(Target):客户端所期望的接口,它定义了客户端可以调用的方法。
  • 适配器(Adapter):将源接口转化为目标接口的适配器,它继承自目标接口,并包含一个源接口对象作为其属性。
  • 源(Adaptee):需要被适配的源接口,它定义了客户端不期望使用的方法。

适用场景

适配器模式通常用于以下场景:

  • 当我们需要使用一些现有的类,并且这些类的接口与我们所需的接口不匹配时。
  • 当我们要复用一些现有的类,并且这些类的实现不能修改时。
  • 当我们需要创建一个可以复用的类库,该类库需要与多个不同的系统或框架进行集成时。

适配器模式的一个经典例子是,在一个软件系统中,我们需要将一些现有的类库集成到我们的系统当中,但是这些类库的接口与我们所需的接口不匹配,这时候就可以使用适配器模式来实现。另外,适配器模式也可以用于将一些不同系统中的组件进行集成,例如将不同的支付方式集成到一个电商网站中。

代码示例

// 适配者接口
interface Adaptee {
  void specificRequest();
}

// 适配者实现类
class ConcreteAdaptee implements Adaptee {
  public void specificRequest() {
    System.out.println("适配者代码被调用!");
  }
}

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

// 适配器类
class Adapter implements Target {
  private Adaptee adaptee;

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

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

// 客户端代码
public class Client {
  public static void main(String[] args) {
    Adaptee adaptee = new ConcreteAdaptee();
    Target target = new Adapter(adaptee);
    target.request();
  }
}

模板模式

模板模式是一种行为型设计模式,它定义了一个操作中的算法框架,将一些步骤延迟到子类中实现。在模板模式中,我们会定义一个抽象类,其中包含一个模板方法,该方法定义了算法的框架,并被其子类重写以提供不同的实现。

模板方法通常由几个基本方法组成,这些方法可以是抽象的、具体的或空的,而实现体现的是这些方法的执行顺序和逻辑。然后我们可以创建一个具体的子类来实现这些方法,从而提供不同的实现。

适用场景

  • 当我们需要定义一个算法框架,并允许其子类提供特定的实现时。
  • 当我们需要实现代码重用时,例如在父类中定义了一些公共方法,可以被多个子类使用。
  • 当我们需要控制算法中某些步骤的执行顺序或者流程时,例如按照固定的流程进行处理。

模板模式通常用于以下场景:

  • 数据库ORM框架:根据数据库模型生成SQL语句、执行SQL语句等。
  • 测试框架:定义测试用例的执行流程,如初始化、执行测试用例、清理等。
  • 游戏开发:游戏引擎中的游戏循环框架、资源加载框架等。

总之,当需要定义一个算法框架,并允许其子类提供特定的实现时,可以使用模板模式。

代码示例

// 定义一个抽象类,其中包含一个模板方法,该方法定义了算法的基本骨架
abstract class AbstractClass {
    public void templateMethod() {
        // 调用基本方法
        primitiveOperation1();
        primitiveOperation2();
    }

    // 基本方法(由子类实现)
    abstract void primitiveOperation1();

    abstract void primitiveOperation2();
}

// 具体子类实现基本方法以完成算法中与特定子类相关的步骤
class ConcreteClass extends AbstractClass {
    void primitiveOperation1() {
        System.out.println("具体类A方法1实现");
    }

    void primitiveOperation2() {
        System.out.println("具体类A方法2实现");
    }
}

public class Client {
    public static void main(String[] args) {
        AbstractClass abstractClass = new ConcreteClass();
        abstractClass.templateMethod();
    }
}

桥接模式

桥接模式是一种结构型设计模式,它将抽象部分和实现部分分离开来,以便两者可以独立地变化。在桥接模式中,我们使用一个抽象类或接口来表示抽象部分,并用另一个实现类来表示实现部分。然后我们将抽象部分和实现部分通过一个桥接对象连接起来,从而使它们可以独立地变化。

桥接模式中包含四个角色:

  • 抽象部分(Abstraction):定义了抽象部分的接口。
  • 实现部分(Implementor):定义了实现部分的接口。
  • 具体抽象部分(Refined Abstraction):继承自抽象部分,并且扩展了抽象部分的接口。
  • 具体实现部分(Concrete Implementor):实现了实现部分的接口。

适用场景

桥接模式通常用于以下场景:

  • 当需要将一个类分成抽象部分和实现部分时,并且需要让它们可以独立地变化时。
  • 当需要使用多个维度来扩展一个类时,例如颜色、尺寸等。
  • 当需要在运行时动态地将实现部分替换为另一个实现时。

桥接模式的一个经典例子是,当我们需要绘制一个形状时,可以使用桥接模式来避免创建多个类。我们可以定义一个抽象的Shape类,并将其连接到一个实现类DrawingAPI上。然后我们可以在具体子类中实现不同的形状并调用DrawingAPI对象来绘制它们。另外,桥接模式还可以用于处理不同操作系统之间的差异,例如将GUI组件与底层操作系统分开处理。

代码示例

// 定义实现类的接口
interface Color {
    public void applyColor();
}

// 创建实现Color接口的具体实现类
class RedColor implements Color {
    public void applyColor() {
        System.out.println("红色.");
    }
}

class BlueColor implements Color {
    public void applyColor() {
        System.out.println("蓝色.");
    }
}

// 使用Color接口创建抽象类Shape
abstract class Shape {
    protected Color color;

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

    abstract public void applyColor();
}

// 创建扩展Shape抽象类的具体类
class Square extends Shape {
    public Square(Color color) {
        super(color);
    }

    public void applyColor() {
        System.out.print("正方形填充颜色 ");
        color.applyColor();
    }
}

class Circle extends Shape {
    public Circle(Color color) {
        super(color);
    }

    public void applyColor() {
        System.out.print("圆形填充颜色 ");
        color.applyColor();
    }
}

// 创建演示类以使用Shape和Color类
public class BridgeDemo {
    public static void main(String[] args) {
        Shape square = new Square(new RedColor());
        square.applyColor();

        Shape circle = new Circle(new BlueColor());
        circle.applyColor();
    }
}


建造者模式

建造者模式是一种创建型设计模式,它允许您创建复杂的对象,而无需了解其内部构造。在建造者模式中,我们将一个复杂的对象分解成多个简单的部件,然后依次将这些部件组合起来,从而形成一个完整的对象。

建造者模式通常包含以下角色:

  • 产品(Product):表示要创建的复杂对象。
  • 抽象建造者(Builder):定义了构建产品所需的各个部件的接口。
  • 具体建造者(Concrete Builder):实现了抽象建造者接口,并且负责实际构建产品的各个部件。
  • 指挥者(Director):负责控制产品的构建流程。

适用场景

建造者模式通常用于以下场景:

  • 当需要创建复杂对象时,例如包含多个部件或配置项的对象。
  • 当需要创建多个不同的产品时,例如在生成器中可以定义不同的生成器子类,每个子类可以创建不同类型的产品。
  • 当需要避免构造函数中有过多的参数或者参数顺序对外部客户端产生侵入性时。

建造者模式的一个经典例子是,在一个游戏中,我们需要构建一个人物角色,该角色包含多个部件,如头、身体、手、脚等,每个部件都可以有不同的属性。在这种情况下,我们可以使用建造者模式来构建该人物角色,将其分解成多个部件,并逐步地组装它们。另外,建造者模式还可以用于创建复杂的数据结构或XML文档等。

代码示例

// 定义产品类
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 void show() {
        System.out.println("产品部件A:" + partA);
        System.out.println("产品部件B:" + partB);
        System.out.println("产品部件C:" + partC);
    }
}

// 抽象建造者类
abstract class Builder {
    // 创建产品对象
    protected Product product = new Product();

    public abstract void buildPartA();

    public abstract void buildPartB();

    public abstract void buildPartC();

    // 返回产品对象
    public Product getResult() {
        return product;
    }
}

// 具体建造者类1
class ConcreteBuilder1 extends Builder {
    public void buildPartA() {
        product.setPartA("建造者模式 PartA");
    }

    public void buildPartB() {
        product.setPartB("建造者模式 PartB");
    }

    public void buildPartC() {
        product.setPartC("建造者模式 PartC");
    }
}

// 具体建造者类2
class ConcreteBuilder2 extends Builder {
    public void buildPartA() {
        product.setPartA("建造者模式 PartX");
    }

    public void buildPartB() {
        product.setPartB("建造者模式 PartY");
    }

    public void buildPartC() {
        product.setPartC("建造者模式 PartZ");
    }
}

// 指挥者类
class Director {
    // 组装产品
    public void construct(Builder builder) {
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
    }
}

public class Client {
    public static void main(String[] args) {
        Director director = new Director();
        Builder builder1 = new ConcreteBuilder1();
        Builder builder2 = new ConcreteBuilder2();

        director.construct(builder1);
        Product product1 = builder1.getResult();
        product1.show();

        director.construct(builder2);
        Product product2 = builder2.getResult();
        product2.show();
    }
}

责任链模式

责任链模式是一种行为型设计模式,它允许您将请求沿着处理者链进行传递,直到其中一个处理者处理该请求。在责任链模式中,我们定义了一个抽象处理者类,该类包含一个指向下一个处理者的引用,并提供了处理请求的方法。然后我们可以创建多个具体处理者类来实现处理请求的不同方式。每个具体处理者类都可以决定是否处理该请求,或者将其传递给下一个处理者。

责任链模式通常包括以下角色:

  • 抽象处理者(Handler):定义了处理请求的接口,并且包含一个指向下一个处理者的引用。
  • 具体处理者(Concrete Handler):实现了抽象处理者接口,并且负责实际处理请求。

适用场景

责任链模式通常用于以下场景:

  • 当我们需要处理不同类型的请求,并且每个请求可能需要由不同的处理者来处理时。
  • 当我们需要避免将请求发送给错误的处理者时,例如在电商网站中,如果某个商品已经售完,就应该立即停止对该商品的下单操作,并提示用户其已售罄。
  • 当我们需要动态地指定可以处理请求的对象集合时。

责任链模式的一个经典例子是,当我们需要处理不同级别的日志记录时,可以使用责任链模式。例如,我们可以定义一个抽象处理者类来表示不同级别的日志记录器,并将其指向下一个处理者。然后对于每个日志消息,我们可以将其传递给第一个处理者,并且只有当该处理者不能处理该请求时,才会将其传递给下一个处理者。另外,在Web应用程序中,责任链模式也可以用于处理HTTP请求。

代码示例

/**
 * 定义一个处理请求的接口
 */
interface Handler {
    void setNextHandler(Handler handler);
    void handleRequest(int request);
}

/**
 * 实现处理请求的接口,具体处理逻辑在子类中实现
 */
abstract class AbstractHandler implements Handler {
    protected Handler nextHandler;

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

    @Override
    public void handleRequest(int request) {
        if (nextHandler != null) {
            nextHandler.handleRequest(request);
        }
    }
}

/**
 * 具体的处理类,处理请求编号为1的请求
 */
class ConcreteHandler1 extends AbstractHandler {
    @Override
    public void handleRequest(int request) {
        if (request == 1) {
            System.out.println("ConcreteHandler1 处理了请求 " + request);
        } else {
            super.handleRequest(request);
        }
    }
}

/**
 * 具体的处理类,处理请求编号为2的请求
 */
class ConcreteHandler2 extends AbstractHandler {
    @Override
    public void handleRequest(int request) {
        if (request == 2) {
            System.out.println("ConcreteHandler2 处理了请求 " + request);
        } else {
            super.handleRequest(request);
        }
    }
}

/**
 * 具体的处理类,处理请求编号为3的请求
 */
class ConcreteHandler3 extends AbstractHandler {
    @Override
    public void handleRequest(int request) {
        if (request == 3) {
            System.out.println("ConcreteHandler3 处理了请求 " + request);
        } else {
            super.handleRequest(request);
        }
    }
}

/**
 * 客户端代码,构建责任链并发送请求
 */
public class Client {
    public static void main(String[] args) {
        // 构建责任链
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        Handler handler3 = new ConcreteHandler3();
        handler1.setNextHandler(handler2);
        handler2.setNextHandler(handler3);

        // 发送请求
        handler1.handleRequest(1);
        handler1.handleRequest(2);
        handler1.handleRequest(3);
    }
}

门面模式

门面模式是一种结构型设计模式,它提供了一个简单的接口来访问复杂系统中的子系统。在门面模式中,我们定义了一个门面类,该类包含了客户端需要使用的所有方法,并且可以将这些方法转换为适合实际子系统的调用。门面模式的目的是简化客户端和子系统之间的交互,并提高代码的可维护性和可读性。

门面模式通常包括以下角色:

  • 门面(Facade):定义了客户端可以访问的所有方法,并将这些方法转换为适合实际子系统的调用。
  • 子系统(SubSystem):实现了门面所定义的接口,并负责实际处理请求。

适用场景

门面模式通常用于以下场景:

  • 当需要简化复杂系统的操作时,例如在大型软件系统中,可能存在多个子系统,每个子系统都有自己的接口和实现方式。如果客户端需要访问多个子系统,那么就需要编写大量的代码来处理各个子系统之间的交互,这时候就可以使用门面模式来简化操作。
  • 当需要解耦客户端和子系统之间的依赖关系时,例如在测试阶段,可能需要替换或模拟子系统的某些组件。

门面模式的一个经典例子是,当我们需要访问多个Web服务时,可以使用门面模式将其封装成一个简单的接口。例如,我们可以定义一个WebServiceFacade类,并将所有的Web服务都封装到这个类中。然后对于客户端来说,只需要调用WebServiceFacade类的方法即可完成与各个Web服务的交互,从而避免了直接访问多个Web服务所带来的复杂性。

代码示例

// 定义一个门面类,提供简单的接口给客户端使用
class Facade {
    private Subsystem1 subsystem1;
    private Subsystem2 subsystem2;
    private Subsystem3 subsystem3;

    public Facade() {
        subsystem1 = new Subsystem1();
        subsystem2 = new Subsystem2();
        subsystem3 = new Subsystem3();
    }

    // 提供一个简单的接口给客户端使用,隐藏了子系统的复杂性
    public void operation() {
        subsystem1.operation1();
        subsystem2.operation2();
        subsystem3.operation3();
    }
}

// 子系统1
class Subsystem1 {
    public void operation1() {
        System.out.println("子系统1的操作");
    }
}

// 子系统2
class Subsystem2 {
    public void operation2() {
        System.out.println("子系统2的操作");
    }
}

// 子系统3
class Subsystem3 {
    public void operation3() {
        System.out.println("子系统3的操作");
    }
}

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

装饰者模式

装饰者模式是一种结构型设计模式,它允许您通过将对象包装在一个装饰器对象中来动态地扩展其功能。在装饰者模式中,我们定义了一个抽象组件类,该类包含了基本的操作方法。然后我们可以创建多个具体组件类,并使用不同的装饰器来为其添加额外的功能。

装饰者模式通常包括以下角色:

  • 抽象组件(Component):定义了基本操作方法。
  • 具体组件(Concrete Component):实现了抽象组件,并且可以被装饰器包装。
  • 抽象装饰器(Decorator):定义了装饰器的接口,并包含一个指向组件的引用。
  • 具体装饰器(Concrete Decorator):实现了抽象装饰器,并且可以为组件添加额外的功能。

适用场景

装饰者模式通常用于以下场景:

  • 当需要动态地扩展对象的功能时,例如在运行时添加、删除或修改对象的某些属性或方法。
  • 当需要避免使用子类来扩展对象的功能时,例如当存在多个功能组合时,如果每个组合都需要创建一个新的子类,那么就会导致类层次结构的膨胀,从而增加代码的复杂性和维护成本。

装饰者模式的一个经典例子是,当我们需要为文本编辑器添加新的功能时,可以使用装饰者模式。例如,我们可以定义一个抽象组件类来表示文本编辑器,并实现基本的编辑功能。然后我们可以创建多个具体组件类来表示不同类型的文本编辑器(如Word、Notepad等),并使用不同的装饰器来增强其功能(如加粗、斜体、下划线等)。另外,在Java I/O库中,也广泛使用了装饰者模式。

代理示例

// 定义一个接口,被装饰者和装饰者都要实现该接口
interface Component {
    void operation();
}

// 被装饰者,实现 Component 接口
class ConcreteComponent implements Component {
    public void operation() {
        System.out.println("具体组件的操作");
    }
}

// 装饰者,也实现 Component 接口
class Decorator implements Component {
    private Component component;

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

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

// 具体的装饰者,扩展 Decorator 类
class ConcreteDecorator extends Decorator {
    public ConcreteDecorator(Component component) {
        super(component);
    }

    public void operation() {
        super.operation();
        addedBehavior();
    }

    public void addedBehavior() {
        System.out.println("为具体组件增加额外的操作");
    }
}

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

迭代器模式

迭代器模式是一种行为型设计模式,它允许您以统一的方式遍历集合中的元素,而无需了解其内部结构。在迭代器模式中,我们定义了一个抽象迭代器接口,其中包含用于遍历集合元素的方法。然后我们可以创建多个具体迭代器类来实现不同的遍历方式。

迭代器模式通常包括以下角色:

  • 抽象迭代器(Iterator):定义了用于遍历集合元素的方法。
  • 具体迭代器(Concrete Iterator):实现了抽象迭代器,并且负责实际遍历集合元素。
  • 集合类(Aggregate):定义了创建迭代器对象的方法,并且可以返回一个迭代器对象。
  • 具体集合类(Concrete Aggregate):实现了集合类接口,并提供了对集合元素的访问方法。

适用场景

迭代器模式通常用于以下场景:

  • 当需要遍历集合中的元素时,并且希望将其与集合的具体实现分离开来时。
  • 当希望以不同的方式遍历集合中的元素时,例如按顺序、随机等。
  • 当需要对集合元素进行增、删、改操作时,而不想破坏遍历的顺序。

迭代器模式的一个经典例子是,当我们需要遍历不同类型的数据结构时,可以使用迭代器模式。例如,我们可以定义一个抽象迭代器接口来表示不同类型的数据结构,并实现基本的遍历方法(如next、hasNext等)。然后我们可以创建多个具体迭代器类来表示不同类型的数据结构,例如链表、数组等,并使用不同的遍历方式来实现这些迭代器。另外,在Java中,集合类库中的Iterator接口就是迭代器模式的一个应用

代码示例

/**
 * 迭代器接口,定义了迭代器的基本操作
 */
interface Iterator {
    boolean hasNext(); // 是否还有下一个元素
    Object next(); // 返回下一个元素
}

/**
 * 集合接口,定义了集合的基本操作
 */
interface Collection {
    Iterator iterator(); // 返回一个迭代器
    int size(); // 返回集合的大小
}

/**
 * 具体迭代器实现类
 */
class ConcreteIterator implements Iterator {
    private ConcreteCollection collection;
    private int pos = -1;

    public ConcreteIterator(ConcreteCollection collection) {
        this.collection = collection;
    }

    @Override
    public boolean hasNext() {
        return pos < collection.size() - 1;
    }

    @Override
    public Object next() {
        if (hasNext()) {
            pos++;
            return collection.get(pos);
        }
        return null;
    }
}

/**
 * 具体集合实现类
 */
class ConcreteCollection implements Collection {
    private Object[] objs = {"A", "B", "C", "D", "E"};

    @Override
    public Iterator iterator() {
        return new ConcreteIterator(this);
    }

    @Override
    public int size() {
        return objs.length;
    }

    public Object get(int index) {
        return objs[index];
    }
} 

// 使用迭代器模式遍历集合
ConcreteCollection collection = new ConcreteCollection();
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

访问者模式

访问者模式是一种行为设计模式,它允许你定义一个独立于对象结构的操作。通过这种方式,可以在不改变对象结构的前提下向对象添加新操作。

该模式涉及到两个核心概念:访问者和被访问者。被访问者是一个包含许多元素的对象结构,而访问者是在这些元素上执行操作的对象。

在访问者模式中,被访问者的元素都实现了一个公共接口,以便访问者可以在不知道具体对象类型的情况下访问每个元素。访问者可以根据自己的需要定义不同的操作,这些操作将在被访问者的所有元素上执行。

适用场景

访问者模式适用于以下场景:

  • 当你需要对一个复杂对象结构中的元素进行很多不同的操作时,但是这些操作可能会随着时间的推移而发生改变。
  • 当你需要在不改变对象结构的情况下向对象添加新操作时。
  • 当你希望分离算法和对象结构时,从而避免让它们彼此混合。

例如,假设您正在编写一个应用程序,该应用程序需要处理图形对象。这些对象可以是圆形、矩形、三角形等。您需要对这些对象执行许多不同的操作,例如计算面积、打印对象信息等。您可以使用访问者模式来定义一个访问者,它可以在这些图形对象上执行这些操作,而无需知道特定的对象类型。这使得将来添加新的图形对象变得更加容易,并且可以轻松地添加新的操作,而不必修改对象结构。

代码示例

// 访问者模式demo

// 首先定义一个抽象元素类
abstract class Element {
    public abstract void accept(Visitor visitor);
}

// 定义具体元素类A
class ConcreteElementA extends Element {
    public void accept(Visitor visitor) {
        visitor.visitConcreteElementA(this);
    }
}

// 定义具体元素类B
class ConcreteElementB extends Element {
    public void accept(Visitor visitor) {
        visitor.visitConcreteElementB(this);
    }
}

// 定义抽象访问者类
abstract class Visitor {
    public abstract void visitConcreteElementA(ConcreteElementA elementA);
    public abstract void visitConcreteElementB(ConcreteElementB elementB);
}

// 定义具体访问者类
class ConcreteVisitor1 extends Visitor {
    public void visitConcreteElementA(ConcreteElementA elementA) {
        System.out.println("具体访问者1访问-->" + elementA.getClass().getSimpleName());
    }

    public void visitConcreteElementB(ConcreteElementB elementB) {
        System.out.println("具体访问者1访问-->" + elementB.getClass().getSimpleName());
    }
}

// 定义具体访问者类
class ConcreteVisitor2 extends Visitor {
    public void visitConcreteElementA(ConcreteElementA elementA) {
        System.out.println("具体访问者2访问-->" + elementA.getClass().getSimpleName());
    }

    public void visitConcreteElementB(ConcreteElementB elementB) {
        System.out.println("具体访问者2访问-->" + elementB.getClass().getSimpleName());
    }
}

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

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

    public void add(Element element) {
        list.add(element);
    }

    public void remove(Element element) {
        list.remove(element);
    }
}

// 测试类
public class Client {
    public static void main(String[] args) {
        ObjectStructure os = new ObjectStructure();
        os.add(new ConcreteElementA());
        os.add(new ConcreteElementB());

        Visitor visitor1 = new ConcreteVisitor1();
        Visitor visitor2 = new ConcreteVisitor2();

        os.accept(visitor1);
        System.out.println("------------------------");
        os.accept(visitor2);
    }
}
Last Updated: