找回密码
 立即注册
首页 业界区 安全 [设计模式/Java] 设计模式之访问者模式【24】 ...

[设计模式/Java] 设计模式之访问者模式【24】

丁若云 2025-5-31 23:55:22



  • 访问者模式可以说是GOF23中设计模式最复杂的一个,但日常开发中使用频率却不高。
所以说上帝喜欢简洁!
增删改查虽然简单,却是大部分程序员日常主要工作,是可以混饭吃的家伙式。
你技术再牛逼,企业用不到,那对于企业来说也没啥用,所以说合适的才是最好的
不常用不等于没有用,这一点的认识到。
概述:访问者模式 := Visitor Pattern ∈ 行为型模式

模式定义


  • 问题背景
访问者模式试图解决如下问题: > 一个类农场里面包含各种元素,例如有大雁,狗子,鸭子。而每个元素的操作却经常变换,一会让大雁排成一字,一会让大雁排成人字。
当大雁排成一字的时候狗子要排成S形状,鸭子要排成B形状,当大雁排成人字时候狗子要叫两声,鸭子要跳起来...。
但对农场这类有要求,第一:可以迭代这些元素,第二:里面的元素不能频繁变动,你不能一会把鸭子杀了吃了,一会又买回一匹马...,
如果是这样的话就不适合使用Visitor模式
如果我们不采用设计模式,那么就要频繁的修改这些元素类,违背了开闭原则,降低代码的可维护和扩展性。

  • 主要解决的问题
解决在稳定数据结构易变操作之间的【耦合】问题,使得操作可以独立于数据结构变化。


  • 模式定义
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下,定义作用于其内部各个元素的新操作
在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。
这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
适用场景


  • 当你有个类,里面的包含各种类型的元素,这个类的结构比较稳定不会经常增删不同类型的元素。而需要经常给这些元素添加新的操作的时候,考虑使用此设计模式。
当需要对一个对象结构中的对象执行多种不同的且不相关的操作时,尤其是这些操作需要避免"污染"对象类本身。
实现步骤


  • 定义元素接口:声明一个接受访问者的方法。
  • 创建具体元素:实现元素接口,每个具体元素类对应数据结构中的一个具体对象。
  • 定义访问者接口(Visitor):声明一系列访问方法,一个访问方法对应数据结构中的一个元素类。
  • 创建具体访问者(Concrete Visitor):实现访问者接口,为每个具体元素类的访问方法提供具体实现。
  • 对象结构(Object Structure)(可选):


  • 定义了如何组装具体元素,如一个组合类。
模式特点

优点


  • 单一职责原则:访问者模式符合单一职责原则,每个类只负责一项职责。
  • 扩展性:容易为数据结构添加新的操作。
  • 灵活性:访问者可以独立于数据结构变化。
缺点


  • 违反迪米特原则:元素需要向访问者公开其内部信息。
  • 元素类难以变更:元素类需要维持与访问者的兼容。
  • 依赖具体类:访问者模式依赖于具体类而不是接口,违反了依赖倒置原则。
使用建议


  • 当对象结构稳定,但需要在其上定义多种新操作时,考虑使用访问者模式。
  • 当需要避免操作"污染"对象类时,使用访问者模式封装操作。
  • 访问者模式可以用于功能统一,如报表生成、用户界面显示、拦截器和过滤器等。
案例实践

CASE 生活场景-朋友家做客


  • 做客场景:访问者(如您)访问朋友家,朋友作为元素提供信息,访问者根据信息做出判断。
CASE 计算机零部件


  • 我们将创建一个定义接受操作的 `ComputerPart 接口。
  • Keyboard、Mouse、Monitor 和 Computer 是实现了 ComputerPart 接口的实体类。
  • 我们将定义另一个接口 ComputerPartVisitor,它定义了访问者类的操作。
  • Computer 使用实体访问者来执行相应的动作。
  • VisitorPatternDemo,我们的演示类使用 Computer、ComputerPartVisitor 类来演示访问者模式的用法。
1.png

ComputerPart : 元素接口
  1. public interface ComputerPart {
  2.    public void accept(ComputerPartVisitor computerPartVisitor);
  3. }
复制代码
Keyboard|Monitor|Mouse|Computer implements ComputerPart : 具体元素


  • Keyboard
  1. public class Keyboard implements ComputerPart {
  2.    @Override
  3.    public void accept(ComputerPartVisitor computerPartVisitor) {
  4.       computerPartVisitor.visit(this);
  5.    }
  6. }
复制代码

  • Monitor
  1. public class Monitor implements ComputerPart {
  2.    @Override
  3.    public void accept(ComputerPartVisitor computerPartVisitor) {
  4.       computerPartVisitor.visit(this);
  5.    }
  6. }
复制代码

  • Mouse
  1. public class Mouse implements ComputerPart {
  2.     @Override
  3.    public void accept(ComputerPartVisitor computerPartVisitor) {
  4.       computerPartVisitor.visit(this);
  5.    }
  6. }
复制代码

  • Computer
  1. public class Computer implements ComputerPart {  
  2.    ComputerPart[] parts;
  3.    public Computer(){
  4.       parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};      
  5.    }
  6.    @Override
  7.    public void accept(ComputerPartVisitor computerPartVisitor) {
  8.       for (int i = 0; i < parts.length; i++) {
  9.          parts[i].accept(computerPartVisitor);
  10.       }
  11.       computerPartVisitor.visit(this);
  12.    }
  13. }
复制代码
ComputerPartVisitor : 访问者接口
  1. //访问者接口 : 声明一系列访问方法,一个访问方法对应数据结构中的一个元素类。
  2. public interface ComputerPartVisitor {
  3.     public void visit(Computer computer);
  4.     public void visit(Mouse mouse);
  5.     public void visit(Keyboard keyboard);
  6.     public void visit(Monitor monitor);
  7. }
复制代码
ComputerPartDisplayVisitor implements ComputerPartVisitor : 具体访问者
  1. public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
  2.    @Override
  3.    public void visit(Computer computer) {
  4.       System.out.println("Displaying Computer.");
  5.    }
  6.    @Override
  7.    public void visit(Mouse mouse) {
  8.       System.out.println("Displaying Mouse.");
  9.    }
  10.    @Override
  11.    public void visit(Keyboard keyboard) {
  12.       System.out.println("Displaying Keyboard.");
  13.    }
  14.    @Override
  15.    public void visit(Monitor monitor) {
  16.       System.out.println("Displaying Monitor.");
  17.    }
  18. }
复制代码
Client

使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。
  1. public class VisitorPatternDemo {
  2.    public static void main(String[] args) {
  3.       ComputerPart computer = new Computer();
  4.       computer.accept(new ComputerPartDisplayVisitor());
  5.    }
  6. }
复制代码
out
  1. Displaying Mouse.
  2. Displaying Keyboard.
  3. Displaying Monitor.
  4. Displaying Computer.
复制代码
Y 推荐文献


  • 设计模式之总述 - 博客园/千千寰宇
X 参考文献


  • 秒懂设计模式之访问者模式(Visitor Pattern) - Zhihu
  • 设计模式: 访问者模式 - 概念、实现及spring中的访问者模式 - CSDN
  • 访问者模式 - 菜鸟教程
    本文作者:        千千寰宇   
    本文链接:         https://www.cnblogs.com/johnnyzen   
    关于博文:评论和私信会在第一时间回复,或直接私信我。   
    版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA     许可协议。转载请注明出处!
    日常交流:大数据与软件开发-QQ交流群: 774386015        【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!   

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册