JS设计模式之访问者模式的用法详解

 更新时间:2023年08月30日 09:52:47   作者:慕仲卿  
JS访问者模式是一种行为型设计模式,用于将算法与对象结构分离, 该模式允许你定义新的操作(访问者)而无需修改现有对象结构(被访问者), 通过这种方式,你可以在不改变对象结构的情况下添加新的操作,本文就给大家详细的讲讲JS访问者模式的用法

定义和特点

访问者模式是一种行为型设计模式,用于将算法与对象结构分离。 该模式允许你定义新的操作(访问者)而无需修改现有对象结构(被访问者)。 通过这种方式,你可以在不改变对象结构的情况下添加新的操作。

参与者

在访问者模式中,有两个主要角色:被访问者和访问者。

  • 被访问者:一个具有一组**元素和方法(method)**的对象结构。
  • 访问者:一个能够对这些元素执行不同**操作(visit)**的对象。
  • 被访问者提供了**接受(accept)**访问者的方法,以便访问者能够在需要时访问元素。

使用流程

  • 首定义访问者接口,其中包含一组访问方法,每个方法对应一种操作。
  • 在被访问者接口中添加一个接受访问者的方法accept,以便访问者可以访问被访问者的元素。
  • 被访问者的具体实现类需要实现这个接收访问者的方法,并**将自身作为参数(this)**传递给访问者的具体访问方法。
  • 创建一个具体的访问者对象v,并将其传递给被访问者的接受方法,即accept(v)
  • 被访问者将根据传递的访问者对象调用相应的访问方法,从而执行特定的操作。 通过这种【改变新建不同结构的访问者,而不修改被访问者】的方式,你可以在不改变被访问者的结构的情况下,为其添加新的操作。

通俗的理解

访问者设计模式有两个部分完成,在实现不同目标的过程中保持其中一方(被访问者)的结构不变,只修改另外一方的结构(访问者)。 也就是牺牲一个保全另外一个。

作用

访问者模式允许你将算法与对象结构分离,并通过定义访问者接口和被访问者接口来实现多态性。 这种模式适用于需要对一个对象结构中的元素进行不同操作的场景,同时又希望保持对象结构的稳定性。

举例

// 被访问者接口:点心店
interface Bakery {
  accept(visitor: CustomerVisitor): void;
  make(): string;
  makePlus(): string;
}
// 具体的被访问者:圆点心店
class CirclePastry implements Bakery {
  // 被访问者的接受方法
  accept(visitor: CustomerVisitor): void {
    // 将自身作为参数(this)传递给访问者的具体访问方法
    visitor?.visitCirclePastry(this);
  }
  make(): string {
    return "制作圆点心";
  }
  makePlus(): string {
    return "制作精品圆点心";
  }
}
// 具体的被访问者:方点心店
class SquarePastry implements Bakery {
  accept(visitor: CustomerVisitor): void {
    visitor?.visitSquarePastry(this);
  }
  make(): string {
    return "制作方点心";
  }
  makePlus(): string {
    return "制作精品方点心";
  }
}
// 访问者接口:顾客
interface CustomerVisitor {
  visitCirclePastry(pastry: CirclePastry): void;
  visitSquarePastry(pastry: SquarePastry): void;
}
// 具体的访问者:点心爱好者
class PastryLover implements CustomerVisitor {
  visitCirclePastry(pastry: CirclePastry): void {
    console.log(`点心爱好者选择了${pastry.make()}`);
  }
  visitSquarePastry(pastry: SquarePastry): void {
    console.log(`点心爱好者选择了${pastry.make()}`);
  }
}
// 使用示例
const circlePastry: Bakery = new CirclePastry();
const squarePastry: Bakery = new SquarePastry();
const pastryLover: CustomerVisitor = new PastryLover();
circlePastry.accept(pastryLover); // 输出:点心爱好者选择了制作圆点心
squarePastry.accept(pastryLover); // 输出:点心爱好者选择了制作方点心
// 在保证被访问者结构的不变的前提下通过修改访问者的结构达到完成不同操作的目的
// 访问者接口:高级顾客
interface CustomerVisitorPlus {
  visitCirclePastry(pastry: CirclePastry): void;
  visitSquarePastry(pastry: SquarePastry): void;
}
// 具体的访问者:高级点心爱好者
class PastryLoverWithMoney implements CustomerVisitorPlus {
  visitCirclePastry(pastry: CirclePastry): void {
    console.log(`点心爱好者选择了${pastry.makePlus()}`);
  }
  visitSquarePastry(pastry: SquarePastry): void {
    console.log(`点心爱好者选择了${pastry.makePlus()}`);
  }
}
const pastryLoverWithMoney: PastryLoverWithMoney = new PastryLoverWithMoney();
circlePastry.accept(pastryLoverWithMoney); // 输出:点心爱好者选择了制作高级圆点心
squarePastry.accept(pastryLoverWithMoney); // 输出:点心爱好者选择了制作高级方点心
// 可以看出来circlePastry和squarePastry都被复用了

Babel插件中的使用

在 Babel 插件中修改 AST(抽象语法树)时,通常会使用访问者模式。

  • 定义访问者:定义一个访问者对象,该对象包含用于处理不同类型的 AST 节点的方法。每个方法对应一种 AST 节点类型,该方法将被调用以访问和处理相应类型的节点。
  • 遍历和修改 AST:通过使用 Babel 提供的遍历器(@babel/traverse),可以遍历整个 AST。在遍历过程中,对于每个访问到的节点,将根据节点的类型调用相应的访问者方法。
  • 修改 AST:在访问者方法中,您可以对 AST 进行修改。这可以涉及更改节点属性、替换节点、添加新节点等操作。通过修改 AST,插件可以实现源代码的转换和重写。

应用场景

  • DOM 操作:在浏览器中,DOM(文档对象模型)表示网页的结构和内容。使用访问者模式,您可以定义一个访问者对象,该对象可以遍历 DOM 树的节点,并执行相应的操作。例如,可以创建一个访问者来查找特定类型的节点、修改节点属性或样式,或执行其他与 DOM 相关的操作。
  • 数据结构操作:JavaScript 中有许多内置的数据结构,如数组、集合、映射等。通过使用访问者模式,您可以定义一个访问者对象,来对这些数据结构进行遍历和操作。例如,可以创建一个访问者来计算数组中的总和、过滤符合特定条件的元素,或者将映射转换为另一种形式。
  • 编译器和解析器:在编译器和解析器中,访问者模式经常被用来处理抽象语法树(AST)。通过定义访问者对象,可以遍历 AST 并执行各种语义分析、优化或代码生成操作。这样可以将复杂的编译器逻辑分离到不同的访问者方法中,使其更易于维护和扩展。
  • 事件处理:在浏览器中,事件处理是非常常见的任务。访问者模式可以用于处理不同类型的事件,并执行相应的操作。例如,可以创建一个访问者来处理鼠标事件、键盘事件或其他用户交互事件。
  • 数据校验和验证:当需要对数据进行复杂的校验和验证时,访问者模式可以提供一种结构化的方法。您可以定义一个访问者对象,该对象遍历数据结构并执行各种校验逻辑。这样可以将校验逻辑从数据结构中分离出来,使其更加可维护和可扩展。

以上就是JS设计模式之访问者模式的用法详解的详细内容,更多关于JS访问者模式的资料请关注脚本之家其它相关文章!

相关文章

  • JavaScript中btoa和atob全局函数示例详解

    JavaScript中btoa和atob全局函数示例详解

    这篇文章主要给大家介绍了关于JavaScript中btoa和atob全局函数的相关资料,atob和btoa是window对象的两个函数,用来编码解码Base64,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-08-08
  • js将字符串中的每一个单词的首字母变为大写其余均为小写

    js将字符串中的每一个单词的首字母变为大写其余均为小写

    本文主要介绍了javascript将字符串中的每一个单词的首字母变为大写其余均为小写的方法。具有一定的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • JavaScript 图片放大镜(可拖放、缩放效果)

    JavaScript 图片放大镜(可拖放、缩放效果)

    背景:很久之前就在marry5.com看到这个效果,当时觉得很神奇,碍于水平有限,没做出来。
    2008-09-09
  • JavaScript本地存储的几种方式小结

    JavaScript本地存储的几种方式小结

    在 JavaScript 中,本地存储指的是将数据保存在用户的浏览器中,能够在页面刷新或关闭后仍然保留,本文给大家介绍了本地存储的几种方式,每种存储方式的特点、区别及应用场景,需要的朋友可以参考下
    2024-12-12
  • 深入学习JavaScript中的promise

    深入学习JavaScript中的promise

    这篇文章主要介绍了深入学习JavaScript中的promise,Promise对象的主要⽤途是通过链式调⽤的结构,将原本回调嵌套的异步处理流程,转化成“对象.then().then()...”的链式结构
    2022-06-06
  • js实现拖拽功能

    js实现拖拽功能

    本文主要介绍了js实现拖拽效果的实例,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-03-03
  • 详解JavaScript 浮点数运算的精度问题

    详解JavaScript 浮点数运算的精度问题

    这篇文章主要介绍了详解JavaScript 浮点数运算的精度问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-07-07
  • JavaScript实现二叉树定义、遍历及查找的方法详解

    JavaScript实现二叉树定义、遍历及查找的方法详解

    这篇文章主要介绍了JavaScript实现二叉树定义、遍历及查找的方法,结合实例形式较为详细的分析了二叉树的相关概念及javascript构建二叉树、遍历、查找二叉树的常用操作技巧,需要的朋友可以参考下
    2017-12-12
  • JavaScript给每一个li节点绑定点击事件的实现方法

    JavaScript给每一个li节点绑定点击事件的实现方法

    这篇文章主要介绍了JavaScript给每一个li节点绑定点击事件的实现方法,包括js循环给li绑定参数不同的点击事件,需要的朋友可以参考下
    2016-12-12
  • JS实现固定时间点执行某任务的代码示例

    JS实现固定时间点执行某任务的代码示例

    在Web前端开发中,有时我们需要在特定的时间点执行某些任务,例如每日定时发送数据报告、每小时更新一次用户界面等,JavaScript 提供了多种方法来实现这一需求,本文将详细介绍如何使用这些工具和技术,并通过丰富的代码示例展示其具体应用,需要的朋友可以参考下
    2025-02-02

最新评论