[设计模式/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 参考文献
 
    本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号