设计模式:访问者模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

news2024/11/23 16:53:21

上一篇《状态模式》                                                                     下一篇《原型模式》

简介:

访问者模式,它是一种将数据操作与数据结构分离的设计模式,它属于行为型模式。访问者模式的基本思想是,针对系统中拥有固定类型数的对象结构(元素),在其内提供一个accept()方法用来接受访问者对象的访问。不同的访问者对同一元素的访问内容不同,使得相同的元素集合可以产生不同的数据结果。accept()方法可以接收不同的访问者对象,然后在内部将自己(元素)转发到接收到的访问者对象的visit()方法内。访问者内部对应类型的visit()方法就会得到回调执行,对元素进行操作。

访问者模式的使用场景:
1、操作复杂且频繁的数据结构:当需要对一个复杂且频繁变化的数据结构进行操作时,如遍历、查找、统计等,使用访问者模式可以提高代码的可维护性和可复用性。
2、数据结构需要频繁修改:如果数据结构需要频繁修改,而操作又需要与数据结构保持相对独立,这时可以使用访问者模式。通过将操作封装在访问者类中,可以在不修改元素类的情况下增加新的操作,降低了元素类和操作之间的耦合度。
3、需要对数据结构进行复杂的操作:当需要对数据结构进行复杂的操作时,如需要对元素进行自定义的访问、更新、删除等操作,使用访问者模式可以将这些操作封装在访问者类中,使代码更加清晰和易于维护。
4、需要对数据结构进行自定义的查询:当需要对数据结构进行自定义的查询时,如需要根据特定条件对元素进行筛选、排序等操作,使用访问者模式可以将查询逻辑封装在访问者类中,使代码更加灵活和可扩展。

访问者模式的创建步骤:
1、定义元素类:首先需要定义元素类,这些元素类构成了数据结构的基本单元。元素类通常具有一些公共的方法,如accept(),用于接受访问者的访问。
2、定义访问者接口:然后需要定义访问者接口,这个接口为元素类定义了访问的方法。访问者接口通常具有一个visit()方法,用于访问元素对象。
3、实现访问者类:接着需要实现访问者接口,创建访问者类。访问者类通常具有visit()方法的具体实现,用于对元素对象进行操作。
实现元素类的accept()方法:在元素类中实现accept()方法,这个方法接受一个访问者对象作为参数,并在内部将自己转发到接收到的访问者对象的visit()方法内。
4、使用访问者模式:最后,可以通过创建元素对象和访问者对象,并调用元素对象的accept()方法来使用访问者模式。accept()方法会将自己转发到访问者对象的visit()方法内,从而实现对元素对象的操作。

访问者模式的优点,主要包括:
1、扩展性好:访问者模式使得增加新的操作变得很容易,只需要添加一个新的访问者类即可。这提高了系统的可扩展性和可维护性。
2、复用性好:访问者模式可以将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。这提高了系统的复用程度,并且可以避免在每个元素类中都重复实现相同的行为。
3、灵活性好:访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。这使得系统更加灵活,能够适应不同的需求和变化。
4、符合单一职责原则:访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。这符合单一职责原则,使得代码更加清晰和易于维护。
5、便于积累状态:每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中将执行操作的状态积累在自己内部,而不是分散到很多的节点对象中。这有利于系统状态的积累和管理。

访问者模式的缺点,主要包括:
1、破坏封装:访问者模式要求访问者对象访问并调用每一个节点对象的操作,这隐含了一个对所有节点对象的要求:它们必须暴露一些自己的操作和内部状态。这破坏了对象的封装性。
2、违反了依赖倒置原则:访问者模式依赖了具体类,而没有依赖抽象类。这违反了依赖倒置原则,使得代码的维护和扩展性降低。
3、增加新的节点类变得困难:每增加一个新的节点都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作。这使得系统的扩展性降低。
4、实现复杂:访问者模式需要定义访问者接口和实现访问者类,这会增加代码的复杂度和维护成本。同时,使用访问者模式需要对数据结构进行修改,这也会增加实现的难度和复杂度。

总之,访问者模式虽然可以提高系统的可扩展性和灵活性,但也存在一些缺点,需要在设计时权衡考虑。

示例:

一、C#访问者模式

以下是一个示例,展示了如何在C#中实现访问者模式:

//首先定义一个访问者接口:
public interface IVisitor  
{  
    void Visit(ConcreteElement1 element);  
    void Visit(ConcreteElement2 element);  
}
//然后定义一个抽象元素类和具体元素类:
public abstract class Element  
{  
    public void Accept(IVisitor visitor)  
    {  
        visitor.Visit(this);  
    }  
}  
  
public class ConcreteElement1 : Element  
{  
    public void SomeOperation1()  
    {  
        Console.WriteLine("ConcreteElement1 operation");  
    }  
}  
  
public class ConcreteElement2 : Element  
{  
    public void SomeOperation2()  
    {  
        Console.WriteLine("ConcreteElement2 operation");  
    }  
}
//接下来定义一个访问者类:
public class Visitor : IVisitor  
{  
    public void Visit(ConcreteElement1 element)  
    {  
        element.SomeOperation1();  
    }  
  
    public void Visit(ConcreteElement2 element)  
    {  
        element.SomeOperation2();  
    }  
}
//最后在客户端代码中使用访问者模式:
public static void Main(string[] args)  
{  
    ConcreteElement1 element1 = new ConcreteElement1();  
    ConcreteElement2 element2 = new ConcreteElement2();  
    Visitor visitor = new Visitor();  
    element1.Accept(visitor); // 调用操作1  
    element2.Accept(visitor); // 调用操作2  
}

二、java访问者模式

访问者模式通常通过以下方式实现:
 

//定义元素接口(Element Interface)
public interface Element {  
    void accept(Visitor visitor);  
}
//定义访问者接口(Visitor Interface)
public interface Visitor {  
    void visit(ConcreteElement1 element);  
    void visit(ConcreteElement2 element);  
}
//创建元素类(Concrete Element Classes)
public class ConcreteElement1 implements Element {  
    @Override  
    public void accept(Visitor visitor) {  
        visitor.visit(this);  
    }  
}    
public class ConcreteElement2 implements Element {  
    @Override  
    public void accept(Visitor visitor) {  
        visitor.visit(this);  
    }  
}
//创建访问者类(Concrete Visitor Classes)
public class Visitor implements Visitor {  
    @Override  
    public void visit(ConcreteElement1 element) {  
        // 对元素对象进行操作  
    }  
  
    @Override  
    public void visit(ConcreteElement2 element) {  
        // 对元素对象进行操作  
    }  
}
//在客户端代码中使用访问者模式
public static void main(String[] args) {  
    ConcreteElement1 element1 = new ConcreteElement1();  
    ConcreteElement2 element2 = new ConcreteElement2();  
    Visitor visitor = new Visitor();  
    element1.accept(visitor); // 调用操作1  
    element2.accept(visitor); // 调用操作2  
}

三、javascript访问者模式

在JavaScript中,访问者实现方式如下:
 

//定义元素接口(Element Interface)
const Element = {  
  accept: function(visitor) {  
    visitor.visit(this);  
  }  
};
//定义访问者接口(Visitor Interface)
const Visitor = {  
  visit: function(element) {  
    // 对元素对象进行操作  
  }  
};
//创建元素类(Concrete Element Classes)
class ConcreteElement1 extends Element {  
  constructor() {  
    super();  
  }  
}  
  
class ConcreteElement2 extends Element {  
  constructor() {  
    super();  
  }  
}
//创建访问者类(Concrete Visitor Classes)
class Visitor1 extends Visitor {  
  visit(element) {  
    // 对元素对象进行操作1  
  }  
}  
  
class Visitor2 extends Visitor {  
  visit(element) {  
    // 对元素对象进行操作2  
  }  
}
//在客户端代码中使用访问者模式
const element1 = new ConcreteElement1();  
const element2 = new ConcreteElement2();  
const visitor1 = new Visitor1();  
const visitor2 = new Visitor2();  
element1.accept(visitor1); // 调用操作1  
element2.accept(visitor2); // 调用操作2

四、C++访问者模式

以下是在C++中实现访问者模式:

//定义元素接口(Element Interface)
class Element {  
public:  
  virtual void accept(Visitor* visitor) = 0;  
};
//定义访问者接口(Visitor Interface)
class Visitor {  
public:  
  virtual void visit(ConcreteElement1* element) = 0;  
  virtual void visit(ConcreteElement2* element) = 0;  
};
//创建元素类(Concrete Element Classes)
class ConcreteElement1 : public Element {  
public:  
  void accept(Visitor* visitor) override {  
    visitor->visit(this);  
  }  
};  
  
class ConcreteElement2 : public Element {  
public:  
  void accept(Visitor* visitor) override {  
    visitor->visit(this);  
  }  
};
//创建访问者类(Concrete Visitor Classes)
class Visitor1 : public Visitor {  
public:  
  void visit(ConcreteElement1* element) override {  
    // 对元素对象进行操作1  
  }  
};  
  
class Visitor2 : public Visitor {  
public:  
  void visit(ConcreteElement2* element) override {  
    // 对元素对象进行操作2  
  }  
};
//在客户端代码中使用访问者模式
int main() {  
	ConcreteElement1* element1 = new ConcreteElement1();  
	ConcreteElement2* element2 = new ConcreteElement2();  
	Visitor* visitor1 = new Visitor1();  
	Visitor* visitor2 = new Visitor2();  
	element1->accept(visitor1); // 调用操作1  
	element2->accept(visitor2); // 调用操作2
}

五、python访问者模式

以下是在python中实现访问者模式:

//定义元素接口(Element Interface)
from abc import ABC, abstractmethod  
  
class Element(ABC):  
    @abstractmethod  
    def accept(self, visitor):  
        pass
//定义访问者接口(Visitor Interface)
class Visitor(ABC):  
    @abstractmethod  
    def visit(self, element):  
        pass
//创建元素类(Concrete Element Classes)
class ConcreteElement1(Element):  
    def accept(self, visitor):  
        visitor.visit(self)  
  
class ConcreteElement2(Element):  
    def accept(self, visitor):  
        visitor.visit(self)
//创建访问者类(Concrete Visitor Classes)
class Visitor1(Visitor):  
    def visit(self, element):  
        # 对元素对象进行操作1  
        pass  
  
class Visitor2(Visitor):  
    def visit(self, element):  
        # 对元素对象进行操作2  
        pass
//在客户端代码中使用访问者模式
if __name__ == '__main__':  
	element1 = ConcreteElement1()  
	element2 = ConcreteElement2()  
	visitor1 = Visitor1()  
	visitor2 = Visitor2()  
	element1.accept(visitor1) # 调用操作1  
	element2.accept(visitor2) # 调用操作2

六、go访问者模式

以下是一个示例,展示了如何在go中实现访问者模式:
 

//首先,定义一个接口,表示元素:
type Element interface {  
 Accept(Visitor)  
}
//然后,定义一个接口,表示访问者:
type Visitor interface {  
 Visit(Element)  
}
//接下来,创建一些具体的元素类和访问者类:
type ConcreteElement1 struct{}  
  
func (e *ConcreteElement1) Accept(v Visitor) {  
 v.Visit(*e)  
}  
  
type ConcreteElement2 struct{}  
  
func (e *ConcreteElement2) Accept(v Visitor) {  
 v.Visit(*e)  
}  
  
type ConcreteVisitor struct{}  
  
func (v *ConcreteVisitor) Visit(e Element) {  
 // 对元素进行操作的具体实现  
 fmt.Println("Visiting ConcreteElement1 or ConcreteElement2")  
}
//最后,在客户端代码中使用访问者模式:
func main() {  
 element1 := &ConcreteElement1{}  
 element2 := &ConcreteElement2{}  
 visitor := &ConcreteVisitor{}  
  
 element1.Accept(visitor) // 调用操作1  
 element2.Accept(visitor) // 调用操作2  
}

七、PHP访问者模式

以下是一个示例,展示了如何在PHP中实现访问者模式:

//首先,定义一个接口,表示元素:
interface Element {  
    public function accept(Visitor $visitor);  
}
//然后,定义一个接口,表示访问者:
interface Visitor {  
    public function visit(Element $element);  
}
//接下来,创建一些具体的元素类和访问者类:
class ConcreteElement implements Element {  
    private $data;  
      
    public function __construct($data) {  
        $this->data = $data;  
    }  
      
    public function accept(Visitor $visitor) {  
        $visitor->visit($this);  
    }  
}  
  
class ConcreteVisitor implements Visitor {  
    public function visit(Element $element) {  
        // 对元素进行操作的具体实现,例如:  
        echo "Visiting element: " . $element->data . "\n";  
    }  
}
//最后,在客户端代码中使用访问者模式:
$element1 = new ConcreteElement("Element 1");  
$element2 = new ConcreteElement("Element 2");  
$visitor = new ConcreteVisitor();  
  
$element1->accept($visitor); // 调用操作1  
$element2->accept($visitor); // 调用操作2


《完结》

上一篇《状态模式》                                                                 下一篇《原型模式》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1144588.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis中的数据类型以及适用场景

1.Redis中的数据类型 Redis中的数据类型包括:String(字符串)、Hash(字典)、List(列表)、Set(集合)、Sorted Set【Zset】(有序集合)。 Redis 所有的数据结构都是一个key对应一个value,不同类型的数据结构之间的差异就在于value的…

电子器件 电阻参数与选型

一、参数 电阻的主要参数有:精度、温度系数和功率三个 1.1 精度 一般有0.1%、1%,5%,10%,15%、25%等,一般精度越高价格也越高。有些场合需要使用高精度的电阻。 其中精度所代表的字母如下: L0.01%P0.02…

建行广东江门分行:科技赋能,数据助力纠“四风”

为进一步深化落实中央八项规定精神,持续加大“四风”问题查处力度,建行驻江门市分行纪检组根据《广东省分行贯彻落实中央八项规定精神持之以恒纠治“四风”实施方案》(建粤党发〔2023〕1号)安排,对驻在市分行开展“四风…

基于ssm实验室管理系统

功能如图所示 摘要 实验室管理系统(Laboratory Management System,简称LMS)是一种基于SSM(Spring、SpringMVC、MyBatis)框架的信息化工具,旨在帮助实验室管理者高效、精确地管理实验室资源、人员和实验数据…

详解Java的八种基本数据类型

目录 Java八种数据类型 注意: 四个大类 整型(byte、short、int、long) 注意 浮点型(float、double) 神奇的代码 注意: 字符型(char) 布尔型(boolean&#xff0…

CondaError: Downloaded bytes did not match Content-Length

问题 使用anaconda下载包文件时,出现了CondaError: Downloaded bytes did not match Content-Length的错误 CondaError: Downloaded bytes did not match Content-Lengthurl: https://conda.anaconda.org/pytorch/win-64/pytorch-2.1.0-py3.11_cuda11.8_cudnn8_0.…

Jmeter(十七):利用jmeter插件收集性能测试结果

利用jmeter插件收集性能测试结果 汇总报告(Summary Report ) 用来收集性能测试过程中的请求以及事务各项指标。通过监听器--汇总报告 可以添加该元件。界面如下图所示 汇总报告界面介绍: 所有数据写入一个文件:保存测试结果到本…

软件测试面试:支付功能如何测试?

前言 相信有很多的小伙伴全面武装好在找工作。那么,作为测试,不管是面试还是笔试,必然要被考验到的就是”测试思维“。在面试中就是体现在如下面试题中: “说说你项目中的xx模块你是如何测试的?” “给你一个购物车&a…

直线模组怎么分类?

直线模组是一种广泛应用于自动化设备、机器人、数控机床、电子设备等领域的精密传动系统。根据不同的分类方式,直线模组可分为多种类型。 一、按照轴数分类 1、单轴直线模组:只有一个移动轴的直线模组,通常用于简单的直线运动和定位。 2、双…

9、定义错误页

在layouts目录下新建error.vue&#xff0c;可以通过layout函数使用布局文件&#xff0c;通过props: [“error”]能拿到错误信息对象。 <template><div>{{ error.statusCode }}: {{ error.message }}</div> </template><script> export default {…

33:深入浅出x86中断机制

背景 我们知道使用0x10号中断&#xff0c;可以在屏幕上打印一个字符。 问题 系统中的 中断 究竟是什么&#xff1f; 生活中的例子 来看一个生活中例子&#xff1a; 小狄的工作方式 在处理紧急事务的时候&#xff0c;不回应同事的技术求助。老板的召唤必须回应&#xff0c;…

Golang教程——配置环境,再探GoLand

文章目录 一、Go是什么&#xff1f;二、环境配置验证配置环境变量 三、安装开发者工具GoLand四、HelloGolang 一、Go是什么&#xff1f; Go&#xff08;也称为Golang&#xff09;是一种开源的编程语言&#xff0c;由Google开发并于2009年首次发布。Go语言旨在提供一种简单、高…

剑指JUC原理-5.synchronized底层原理

Java对象头 以32位虚拟机为例&#xff1a; 普通对象 在Java虚拟机中&#xff0c;每个对象都有一个对象头&#xff08;Object Header&#xff09;&#xff0c;其中包含了一些用于管理对象的元数据信息。对象头通常由两部分组成&#xff1a;mark word&#xff08;标记字&#x…

开源3D激光(视觉)SLAM算法汇总(持续更新)

目录 一、Cartographer 二、hdl_graph_slam 三、LOAM 四、LeGO-LOAM 五、LIO-SAM 六、S-LOAM 七、M-LOAM 八、livox-loam 九、Livox-Mapping 十、LIO-Livox 十一、FAST-LIO2 十二、LVI-SAM 十三、FAST-Livo 十四、R3LIVE 十五、ImMesh 十六、Point-LIO 一、Cartographer Cartog…

目标检测类项目数据集汇总

一、玩手机数据集及检测 玩手机数据集下载地址分享: https://download.csdn.net/download/qq_34717531/19870205 二、狗的数据集及检测 狗目标检测数据集下载地址分享:https://download.csdn.net/download/qq_34717531/20813390 三、猫数据集及检测 猫数据集下载地址分享: ht…

review-java-basis

Path环境变量用于记住程序路径&#xff0c;方便在命令行窗口的任意目录启动程序 \n代表换行的意思&#xff0c;/t代表一个tab前进一格 强转可能导致数据的丢失&#xff08;溢出&#xff09; 浮点型转换为整型&#xff0c;直接丢掉小数部分&#xff0c;保留整数部分返回 数据类…

GPT的广泛应用会对互联网公司造成挑战吗?——探讨GPT在实际使用中的应用和影响

文章目录 前言GPT 技术的背景和发展历程GPT 技术对互联网行业的影响GPT 技术在互联网行业中的应用GPT 技术对于用户隐私和数据安全的威胁GPT 技术对于人类工作岗位的影响加强 AI 伦理和监管加强 AI 安全性和隐私保护推动 AI 创新和发展&#xff0c;避免过度依赖 AIGPT 技术是一…

日常软件游戏丢失msvcp120dll怎么修复?分享5个修复方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp120dll丢失”。那么&#xff0c;究竟什么是msvcp120dll文件&#xff1f;当它丢失时&#xff0c;我们会遇到哪些问题呢&#xff1f;本文将从以下几个方面进行详细阐述。 msvcp120dll是…

Groovy安装开发环境

准备下载GDK并安装环境变量,跟安装JDK一模一样 https://groovy.apache.org/download.html

【C++】详解map和set基本接口及使用

文章目录 一、关联式容器与键值对1.1关联式容器&#xff08;之前学的都是序列容器&#xff09;1.2键值对pairmake_pair函数&#xff08;map在插入的时候会很方便&#xff09; 1.3树形结构的关联式容器 二、set2.1set的基本介绍2.1默认构造、迭代器区间构造、拷贝构造&#xff0…