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

  • 访问者模式可以说是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 类来演示访问者模式的用法。

ComputerPart : 元素接口

public interface ComputerPart {
   public void accept(ComputerPartVisitor computerPartVisitor);
}

Keyboard|Monitor|Mouse|Computer implements ComputerPart : 具体元素

  • Keyboard
public class Keyboard implements ComputerPart {
   @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      computerPartVisitor.visit(this);
   }
}
  • Monitor
public class Monitor implements ComputerPart { 
   @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      computerPartVisitor.visit(this);
   }
}
  • Mouse
public class Mouse implements ComputerPart {
    @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      computerPartVisitor.visit(this);
   }
}
  • Computer
public class Computer implements ComputerPart {  
   ComputerPart[] parts;
 
   public Computer(){
      parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};      
   } 
 
 
   @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      for (int i = 0; i < parts.length; i++) {
         parts[i].accept(computerPartVisitor);
      }
      computerPartVisitor.visit(this);
   }
}

ComputerPartVisitor : 访问者接口

//访问者接口 : 声明一系列访问方法,一个访问方法对应数据结构中的一个元素类。
public interface ComputerPartVisitor {
    public void visit(Computer computer);
    public void visit(Mouse mouse);
    public void visit(Keyboard keyboard);
    public void visit(Monitor monitor);
}

ComputerPartDisplayVisitor implements ComputerPartVisitor : 具体访问者

public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
   @Override
   public void visit(Computer computer) {
      System.out.println("Displaying Computer.");
   }
 
   @Override
   public void visit(Mouse mouse) {
      System.out.println("Displaying Mouse.");
   }
 
   @Override
   public void visit(Keyboard keyboard) {
      System.out.println("Displaying Keyboard.");
   }
 
   @Override
   public void visit(Monitor monitor) {
      System.out.println("Displaying Monitor.");
   }
}

Client

使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。

public class VisitorPatternDemo {
   public static void main(String[] args) {
      ComputerPart computer = new Computer();
      computer.accept(new ComputerPartDisplayVisitor());
   }
}

out

Displaying Mouse.
Displaying Keyboard.
Displaying Monitor.
Displaying Computer.

Y 推荐文献

X 参考文献

posted @ 2025-04-24 20:38  千千寰宇  阅读(53)  评论(0)    收藏  举报