前端设计模式——访问者模式

80 阅读3分钟

访问者模式(Visitor Pattern)是一种行为型设计模式,它允许在不改变对象结构的前提下,定义用于访问和操作对象元素的新操作。访问者模式是一种双重分派技术,它将方法调用与元素类型分离开来,使得新增操作变得容易。

在访问者模式中,通常有两种角色:

  1. 访问者(Visitor):定义了对每个元素的访问操作,也就是我们需要对元素进行的操作。
  2. 元素(Element):定义了一个 accept() 方法,用来接受访问者的访问。

访问者模式的基本思想是,通过在元素类中定义接受访问者的方法 accept(),并将访问者作为参数传入,让访问者通过访问该元素来完成其特定的操作。访问者模式可以减少对象之间的耦合度,同时也可以增加新的操作而不会对已有的代码产生影响,因此访问者模式通常被用来处理复杂的对象结构。

访问者模式虽然具有灵活性和可扩展性,但也存在一些缺点,例如访问者的新增可能会导致元素类的修改,增加了代码的复杂度,同时也可能影响代码的性能。因此在使用访问者模式时,需要权衡其优缺点并根据具体情况进行选择。

TypeScript 实现

  1. 定义元素接口(Element Interface)和访问者接口(Visitor Interface),并在其中分别定义对应的方法。
// 元素接口
interface Element {
  accept(visitor: Visitor): void;
}

// 访问者接口
interface Visitor {
  visitConcreteElementA(element: ConcreteElementA): void;
  visitConcreteElementB(element: ConcreteElementB): void;
}
  1. 定义具体元素类(Concrete Element Class),并在其中实现 accept() 方法,该方法接收访问者对象,并将自身作为参数传递给访问者。
// 具体元素类A
class ConcreteElementA implements Element {
  public accept(visitor: Visitor): void {
    visitor.visitConcreteElementA(this);
  }
}

// 具体元素类B
class ConcreteElementB implements Element {
  public accept(visitor: Visitor): void {
    visitor.visitConcreteElementB(this);
  }
}
  1. 定义具体访问者类(Concrete Visitor Class),并在其中实现访问者接口中的方法,对元素进行具体的操作。
// 具体访问者类
class ConcreteVisitor implements Visitor {
  public visitConcreteElementA(element: ConcreteElementA): void {
    console.log("ConcreteVisitor is visiting ConcreteElementA");
  }

  public visitConcreteElementB(element: ConcreteElementB): void {
    console.log("ConcreteVisitor is visiting ConcreteElementB");
  }
}
  1. 创建对象结构(Object Structure),将元素添加到其中,并调用 accept() 方法,将访问者作为参数传递进去。
// 创建对象结构
const elements: Element[] = [new ConcreteElementA(), new ConcreteElementB()];

// 创建具体访问者对象
const visitor = new ConcreteVisitor();

// 对象结构中的元素接受访问者的访问
elements.forEach((element) => {
  element.accept(visitor);
});

通过以上步骤,我们就可以在 TypeScript 中实现访问者模式了。在实际开发中,我们可以根据具体情况进行适当的调整和扩展。

JavaScript 实现

  1. 定义元素类(Element Class),并在其中实现 accept() 方法,该方法接收访问者对象,并将自身作为参数传递给访问者。
// 元素类
class Element {
  accept(visitor) {
    throw new Error("This method must be overwritten!");
  }
}

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

// 具体元素类B
class ConcreteElementB extends Element {
  accept(visitor) {
    visitor.visitConcreteElementB(this);
  }
}
  1. 定义访问者类(Visitor Class),并在其中实现访问者接口中的方法,对元素进行具体的操作。
// 访问者类
class Visitor {
  visitConcreteElementA(element) {
    console.log("Visitor is visiting ConcreteElementA");
  }

  visitConcreteElementB(element) {
    console.log("Visitor is visiting ConcreteElementB");
  }
}
  1. 创建对象结构(Object Structure),将元素添加到其中,并调用 accept() 方法,将访问者作为参数传递进去。
// 创建对象结构
const elements = [new ConcreteElementA(), new ConcreteElementB()];

// 创建访问者对象
const visitor = new Visitor();

// 对象结构中的元素接受访问者的访问
elements.forEach((element) => {
  element.accept(visitor);
});