Skip to content

访问者模式

访问者模式(Visitor Pattern)是 行为型设计模式 之一,它允许你在不修改对象结构的前提下(在此模式下,通常是不需要修改数据结构的场景),为对象结构中的元素定义新的操作。换句话说,它将“数据结构”与“作用于数据结构上的操作”分离,使得可以在不改变这些元素类的情况下增加新的操作。也可以理解为,同一数据结构在不同场景下执行不同操作。

核心思想

  • 算法对象结构分离。
  • 通过“双重分派”实现动态绑定。
  • 新增操作时,只需添加一个新的访问者,而无需修改已有类。

角色组成

  1. Visitor(抽象访问者) 定义对每个具体元素(Element)访问的操作接口,如 visit(ElementA)visit(ElementB)

  2. ConcreteVisitor(具体访问者) 实现抽象访问者中定义的操作,即具体的业务逻辑(如打印、统计、计算等)。

  3. Element(抽象元素) 定义一个 accept(Visitor visitor) 方法,表示接受访问者访问。

  4. ConcreteElement(具体元素) 实现 accept() 方法,通常调用访问者的 visit(this) 方法。

  5. ObjectStructure(对象结构) 可以是集合、组合结构等,能够枚举其中的元素,并提供一个高层接口让访问者访问所有元素

代码实现:

typescript
//定义元素抽象类
abstract class IElement {
  public name: string
  //实现该接口的类必须实现一个accept方法
  abstract accept(visit: Visitor): void
}

//构建固定的角色类<前端开发>
class FrontendDevelopment implements IElement {
  public name: string = 'FrontendDevelopment'
  public accept(visitor: Visitor) {
    visitor.visitFrontEnd(this)
  }
}

//构建固定的角色类<后端开发>
class BackendDevelopment implements IElement {
  public name: string = 'backendDevelopment'
  public accept(visitor: Visitor): void {
    visitor.visitBackEnd(this)
  }
}

//定义visitor的抽象接口
abstract class Visitor {
  abstract visitFrontEnd(frontend: FrontendDevelopment): void
  abstract visitBackEnd(backend: BackendDevelopment): void
}

//实现一个软件开发公司类
class SoftwareCompany {
  private members = [] as (FrontendDevelopment | BackendDevelopment)[]
  constructor() {
    this.members.push(new FrontendDevelopment())
    this.members.push(new BackendDevelopment())
  }

  public startProject(visitor: Visitor) {
    this.members.forEach((i) => i.accept(visitor))
  }
}

//实现具体的访问者类
class WechaApp implements Visitor {
  visitFrontEnd(frontend: FrontendDevelopment): void {
    console.log(`[ ${frontend.name} ] >`, `在仿微信小程序做前端开发任务`)
  }
  visitBackEnd(backend: BackendDevelopment): void {
    console.log(`[ ${backend.name} ] >`, `在仿微信小程序做后端开发任务`)
  }
}

class GameApp implements Visitor {
  visitFrontEnd(frontend: FrontendDevelopment): void {
    console.log(`[ ${frontend.name} ] >`, `在仿游戏app开发做前端开发任务`)
  }
  visitBackEnd(backend: BackendDevelopment): void {
    console.log(`[ ${backend.name} ] >`, `在仿游戏开发app做后端端开发任务`)
  }
}

const company = new SoftwareCompany()

company.startProject(new WechaApp())
company.startProject(new GameApp())