【访问者设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

这篇具有很好参考价值的文章主要介绍了【访问者设计模式详解】C/Java/JS/Go/Python/TS不同语言实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

访问者模式(Visitor Pattern)是一种行为型模式。它封装一个访问者类,把各元素类的操作集合起来,目的是将数据结构与数据操作分离。在不改变原有元素类数据结构的前提下,改变了元素类的执行算法。

当某些较为稳定的东西(数据结构或算法),不想直接被改变但又想扩展功能,这时候适合用访问者模式。访问者模式的使用频率并不是很高,大多数情况下,你并不需要使用访问者模式,但是当你一旦需要使用它时,那你就是需要使用它了。

访问者模式有以下几个角色:

  • 结构对象(ObjectStructure):结构对象角色,这是访问者模式的基础角色,包含多个类或者接口.
  • 抽象元素(Element):定义一个接受访问操作accept(),以一个访问者Visitor作为参数。
  • 具体元素(ConcreteElement):实现抽象节点的accept()方法和处理操作,调用Vistor的访问方法实现具体功能。
  • 抽象访问者(Visitor):定义一个抽象接口,声明一个或多个访问操作,使得所有具体访问者都必须实现。
  • 具体访问者(ConcreteVisitor):具体访问者角色,实现Visitor声明的接口。

作用

  1. 在数据基础类里面有一个方法接受访问者,将自身引用传入访问者,从而把不变的固定起来,把变化的开放出去。
  2. 通过隔离类中变化的东西,固定不变的东西,符合单一职责原则,同时具备较好的扩展性和灵活性。

实现步骤

  1. 先创建基本元素抽象类Element,确定accept()抽象方法。
  2. 分别创建几个具体的元素类,实现抽象元素的accept方法。
  3. 在创建Visitor抽象接口,定义visit方法,调用具体元素。
  4. 创建1个或多个Visitor类,继承抽象接口,客户将以此去访问具体元素。
  5. 再创建对象结构类,这是核心入口类,负责组合各种元素,以及传递访问者Visitor。
  6. 客户调用时先创建对象结构类,再指定访问者类,通过访问这类调用具体元素类

UML

【访问者设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

 

Java代码

结构对象

// ObjectStructure.java 结构对象(ObjectStructure)
public class ObjectStructure {

  // 可以想象为一台电脑,聚合了各种设备元素
  private String name = "Computer Structure";
  private List<Element> elements = new ArrayList<Element>();

  // 结构对象初始化聚合了其他元素
  public ObjectStructure() {
    addElement(new ConcreteElementA());
    addElement(new ConcreteElementB());
  }

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

  // 传入访问者分发给其他元素
  public void accept(Visitor visitor) {
    System.out
        .println("ObjectStructure::accept() [visitor.class = " + visitor.getClass().getSimpleName() + " visitor.name = "
            + visitor.getName() + "]");
    for (Element element : elements) {
      element.accept(visitor);
    }
  }

  public String getName() {
    return this.name;
  }

}

抽象访问者类

// Visitor.java 访问者Visitor抽象接口,定义不同的visit方法
public interface Visitor {
  public void visit(ConcreteElementA concreteElementA);

  public void visit(ConcreteElementB concreteElementB);

  public String getName();
}

具体访问者

// ConcreteVisitorA.java 具体访问者A
public class ConcreteVisitorA implements Visitor {

  // 假如由不同厂商是程序的访问者
  private String name = "Google Visitor";

  @Override
  public void visit(ConcreteElementA concreteElementA) {
    System.out.println(
        "ConcreteVisitorA::visit() [Element.class = " + concreteElementA.getClass().getSimpleName()
            + " Element.name = "
            + concreteElementA.getName() + "]");
    concreteElementA.operate();
  }

  @Override
  public void visit(ConcreteElementB concreteElementB) {
    System.out.println("ConcreteVisitorA::visit() [Element.class = " + concreteElementB.getClass().getSimpleName()
        + " Element.name = "
        + concreteElementB.getName() + "]");
    concreteElementB.operate();
  }

  public String getName() {
    return this.name;
  }
}
// ConcreteVisitorB.java 具体访问者B
public class ConcreteVisitorB implements Visitor {

  // 假如由不同厂商是程序的访问者
  private String name = "Apple Visitor";

  @Override
  public void visit(ConcreteElementA concreteElementA) {
    System.out.println(
        "ConcreteVisitorB::visit() [Element.class = " + concreteElementA.getClass().getSimpleName()
            + " Element.name = "
            + concreteElementA.getName() + "]");
    concreteElementA.operate();
  }

  @Override
  public void visit(ConcreteElementB concreteElementB) {
    System.out.println(
        "ConcreteVisitorB::visit() [Element.class = " + concreteElementB.getClass().getSimpleName()
            + " Element.name = "
            + concreteElementB.getName() + "]");
    concreteElementB.operate();
  }

  public String getName() {
    return this.name;

  }
}

抽象元素类

// Element.java 抽象元素(Element),定义accept方法,传入抽象访问者
abstract class Element {
  public abstract void accept(Visitor visitor);
}

具体元素实现类

// ConcreteElementA.java 具体的元素实现者A
public class ConcreteElementA extends Element {
  // 可以设想为显示器
  private String name = "Monitor Element";

  @Override
  public void accept(Visitor visitor) {
    System.out
        .println(
            "ConcreteElementA::accept() [visitor.class = " + visitor.getClass().getSimpleName() + " visitor.name = "
                + visitor.getName() + "]");
    visitor.visit(this);
  }

  public void operate() {
    System.out.println("ConcreteElementA::operate() [" + this.getName() + "]");
  }

  public String getName() {
    return this.name;
  }
}
// ConcreteElementB.java 具体的元素实现者B
public class ConcreteElementB extends Element {
  private String name = "Keyboard Element";

  @Override
  public void accept(Visitor visitor) {
    System.out.println(
        "ConcreteElementB::accept() [visitor.class = " + visitor.getClass().getSimpleName() + " visitor.name = "
            + visitor.getName() + "]");
    visitor.visit(this);
  }

  public void operate() {
    System.out.println("ConcreteElementB::operate() [" + this.getName() + "]");
  }

  public String getName() {
    return this.name;
  }
}

测试调用

  /**
   * 访问者模式是当客户需要访问具体各元素Element时,先建立一个访问者Visitor作为媒介
   * 客户基于对象结构ObjectStructure,调用accept(),接受传入的访问者
   * 对象结构向其他元素负责分发访问者,元素对象接受之后会将自己回传给访问者,从而访问者可以访问具体元素
   */
    ObjectStructure structure = new ObjectStructure();
    // 接受访问者A,把访问者传递给具体元素
    structure.accept(new ConcreteVisitorA());

    System.out.println("====");
    // 接受访问者B,把访问者传递给具体元素
    structure.accept(new ConcreteVisitorB());

Go代码

结构对象

// ObjectStructure.go 结构对象(ObjectStructure)
type ObjectStructure struct {
  name     string
  elements []Element
}

func (o *ObjectStructure) AddElement(e Element) {
  o.elements = append(o.elements, e)
}

// 传入访问者分发给其他元素
func (o *ObjectStructure) Accept(v Visitor) {
  fmt.Println(
    "ObjectStructure::Accept() [Visitor.name = " +
      v.GetName() + "]")

  // 通知全部元素成员接受访问者
  for i := 0; i < len(o.elements); i++ {
    o.elements[i].Accept(v)
  }

  // for _, ele := range o.elements {
  //   ele.Accept(v)
  // }
}

func (o *ObjectStructure) GetName() string {
  o.name = "Computer Structure"
  return o.name
}

// 结构对象的初始化函数
func (o *ObjectStructure) Init() {
  // 可以想象为一台电脑,聚合了各种设备元素
  fmt.Println("ObjectStructure::Init() ", o.GetName())
  // 定义一个对象数组,长度可选
  o.elements = make([]Element, 0, 100)

  // 结构对象初始化聚合了其他元素
  o.AddElement(&ConcreteElementA{})
  o.AddElement(&ConcreteElementB{})
}

抽象访问者类

// Visitor.go 访问者Visitor抽象接口,定义不同的visit方法
type Visitor interface {
  VisitA(e *ConcreteElementA)
  VisitB(e *ConcreteElementB)
  GetName() string
}

具体访问者

// ConcreteVisitorA.go 具体访问者A
type ConcreteVisitorA struct {
  name string
}

func (v *ConcreteVisitorA) GetName() string {
  v.name = "Google Visitor(struct=ConcreteVisitorA)"
  return v.name
}

func (v *ConcreteVisitorA) VisitA(e *ConcreteElementA) {
  fmt.Println(
    "ConcreteVisitorA::VisitA() [Element.name = " + e.GetName() + "]")
  e.Operate()
}

func (v *ConcreteVisitorA) VisitB(e *ConcreteElementB) {
  fmt.Println(
    "ConcreteVisitorA::VisitB() [Element.name = " + e.GetName() + "]")
  e.Operate()
}
// ConcreteVisitorB.go 具体访问者B
type ConcreteVisitorB struct {
  name string
}

func (v *ConcreteVisitorB) GetName() string {
  v.name = "Apple Visitor(struct=ConcreteVisitorB)"
  return v.name
}

func (v *ConcreteVisitorB) VisitB(e *ConcreteElementB) {
  fmt.Println(
    "ConcreteVisitorB::VisitB() [Element.name = " + e.GetName() + "]")
  e.Operate()
}

func (v *ConcreteVisitorB) VisitA(e *ConcreteElementA) {
  fmt.Println(
    "ConcreteVisitorB::VisitA() [Element.name = " + e.GetName() + "]")
  e.Operate()
}

抽象元素类

// Element.go 抽象元素(Element),定义accept方法,传入抽象访问者
// go无抽象类,用interface替代
type Element interface {
  Accept(v Visitor)
  Operate()
  GetName() string
}

具体元素实现类

// ConcreteElementA.go 具体的元素实现者A
type ConcreteElementA struct {
  name string
}

func (c *ConcreteElementA) GetName() string {
  c.name = `Monitor Element(struct=ConcreteElementA)`
  return c.name
}

func (e *ConcreteElementA) Accept(v Visitor) {
  fmt.Println(
    "ConcreteElementA::Accept() [Visitor.name = " + v.GetName() + "]")
  v.VisitA(e)
}

func (e *ConcreteElementA) Operate() {
  fmt.Println("ConcreteElementA::Operate() [" + e.GetName() + "]")
}
// ConcreteElementB.go 具体的元素实现者B
type ConcreteElementB struct {
  name string
}

func (c *ConcreteElementB) GetName() string {
  c.name = "Keyboard Element(struct=ConcreteElementB)"
  return c.name
}

func (e *ConcreteElementB) Accept(v Visitor) {
  fmt.Println(
    "ConcreteElementB::Accept() [Visitor.name = " + v.GetName() + "]")
  v.VisitB(e)
}

func (e *ConcreteElementB) Operate() {
  fmt.Println("ConcreteElementB::Operate() [" + e.GetName() + "]")
}

测试调用

func main() {
  fmt.Println("test start:")

  /**
   * 访问者模式是当客户需要访问具体各元素Element时,先建立一个访问者Visitor作为媒介
   * 客户基于对象结构ObjectStructure,调用Accept(),接受传入的访问者
   * 对象结构向其他元素负责分发访问者,元素对象接受之后会将自己回传给访问者,从而访问者可以访问具体元素
   */
  structure := src.ObjectStructure{}
  structure.Init()
  // 接受访问者A,把访问者传递给具体元素
  structure.Accept(&src.ConcreteVisitorA{})

  fmt.Println("====")
  // 接受访问者B,把访问者传递给具体元素
  structure.Accept(&src.ConcreteVisitorB{})
}

更多语言版本

不同语言设计模式源码:https://github.com/microwind/design-pattern文章来源地址https://www.toymoban.com/news/detail-433233.html

到了这里,关于【访问者设计模式详解】C/Java/JS/Go/Python/TS不同语言实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 设计模式之-访问者模式,快速掌握访问者模式,通俗易懂的讲解访问者模式以及它的使用场景

    当谈到访问者模式时,我们可以通过以下方式进行详细解释: 访问者模式是一种行为型设计模式,它允许你在不修改已有代码的情况下,向现有对象结构添加新的操作。该模式将操作(或方法)封装在称为访问者的独立对象中,使得可以在不修改元素类的情况下,通过访问者

    2024年02月03日
    浏览(40)
  • 设计模式——访问者模式

    访问者模式(Visitor Pattern)是一种行为型设计模式,它主要用于在不修改现有类结构的前提下向对象结构添加新的操作。访问者模式通过定义一个访问者接口,使得可以在不改变元素类的情况下,为各个元素类增加新的功能。 元素接口(Element Interface): 定义了一个accept()方法

    2024年01月18日
    浏览(39)
  • 设计模式—访问者模式

     需求:店铺采购了一批水果(苹果及橘子),现在市场监督局来店里检查过期的水果。 如果此时再添加一个操作:找出新品上市的水果。 上述代码中,FruitMarket为应付新增操作,增加了相应的方法来满足要求,但这样破坏了FruitMarket的结构。 本质是将数据结构和数据操作分

    2024年02月10日
    浏览(43)
  • 设计模式——19. 访问者模式

    访问者模式(Visitor Pattern)是一种行为型设计模式,它允许你在不改变元素类(被访问者)的前提下,定义对元素的新操作(访问者),并将这些操作封装到独立的访问者类中。这样,你可以在不修改被访问者的类的情况下,通过不同的访问者来执行不同的操作。 访问者模式

    2024年02月07日
    浏览(25)
  • js设计模式:访问者模式

    将操作方法封装在一个访问者对象中,而不是封装在每个被访问对象当中。 访问者对象可以通过调用被访问者的接口,用来操作被访问者。

    2024年02月22日
    浏览(36)
  • 设计模式之访问者模式(上)

    访问者模式 1)概述 1.概念 访问者模式包含 访问者 和 被访问元素 两个主要组成部分。 处方单中的各种药品信息就是 被访问的元素 ,而划价人员和药房工作人员就是 访问者 ,被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。 被访问元素

    2024年04月25日
    浏览(28)
  • 设计模式之访问者模式(下)

    3)访问者模式与组合模式联用 1.概述 在访问者模式中,包含一个用于存储元素对象集合的对象结构,可以使用迭代器来遍历对象结构,同时具体元素之间可以存在整体与部分关系,有些元素作为容器对象,有些元素作为成员对象,可以使用组合模式来组织元素。 2.结构图

    2024年04月25日
    浏览(29)
  • 设计模式:访问者模式(C++实现)

    访问者模式通过将对元素的操作与元素本身分离,使得可以在不修改元素类的情况下定义新的操作。 运行结果: 在上述代码中,Visitor是访问者接口,定义了访问具体元素的方法。Element是元素接口,定义了接受访问者访问的方法。ConcreteElementA和ConcreteElementB是具体元素类,实

    2024年02月07日
    浏览(37)
  • 设计模式(二十三)访问者

    表示一个作用于某对象结构中的各个元素的操作。访问者模式让你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式 访问者模式是一种较为复杂的行为型模式,它包含访问者和被访问元素两个主要组成部分,这些被访问的元素

    2024年02月19日
    浏览(24)
  • 【设计模式与范式:行为型】69 | 访问者模式(下):为什么支持双分派的语言不需要访问者模式?

    上一节课中,我们学习了访问者模式的原理和实现,并且还原了访问者模式诞生的思维过程。总体上来讲,这个模式的代码实现比较难,所以应用场景并不多。从应用开发的角度来说,它的确不是我们学习的重点。 不过,我们前面反复说过,学习我的专栏,并不只是让你掌握

    2024年02月10日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包