个人学习笔记分享,当前能力有限,请勿贬低,菜鸟互学,大佬绕道
如有勘误,欢迎指出和讨论,本文后期也会进行修正和补充
生活中,同一类对象会存在不同的元素,每种元素也存在多种不同的逻辑和处理方式。
比如医生开的处方药,医生会给出不同的组合,患者也有不同的剂量和使用方式;电脑中的不同零件,我们需要根据不同的需求进行采购和组合,以及使用;
这些数据结构相对稳定,但访问方式多种多样。
我们可以用访问者模式,把访问方式从数据结构分离出来,并根据需求定制处理方法。进而避免在扩展的时候,修改数据结构。
1.定义
使用目的:将数据结构与数据操作分离
使用时机:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中。
解决问题:稳定的数据结构和易变的操作耦合问题。
实现方法:在被访问的类里面加一个对外提供接待访问者的接口。
应用实例:计算机中的组件;医生开的药;
优点:
- 符合单一职责原则。
- 优秀的扩展性。
- 灵活性高。
缺点:
- 具体元素对访问者公布细节,违反了迪米特原则。
- 具体元素变更比较困难。
- 违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
注意事项:访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。
2.结构
访问者模式包含以下主要角色。
- 抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
- 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
- 抽象元素(Element)角色:声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
- 具体元素(ConcreteElement)角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
- 对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。
3.步骤
-
创建抽象访问者
interface ComputerPartVisitor { void visit(Computer computer); void visit(Mouse mouse); void visit(Keyboard keyboard); }
-
创建抽象元素类
interface ComputerPart { void accept(ComputerPartVisitor computerPartVisitor); }
-
创建具体元素类
// 具体元素类-computer class Computer implements ComputerPart { private List<ComputerPart> parts; public Computer() { parts = List.of(new Mouse(), new Keyboard()); } @Override public void accept(ComputerPartVisitor computerPartVisitor) { parts.forEach(m -> m.accept(computerPartVisitor)); computerPartVisitor.visit(this); } } // 具体元素类-mouse class Mouse implements ComputerPart { @Override public void accept(ComputerPartVisitor computerPartVisitor) { computerPartVisitor.visit(this); } } // 具体元素类-keyboard class Keyboard implements ComputerPart { @Override public void accept(ComputerPartVisitor computerPartVisitor) { computerPartVisitor.visit(this); } }
-
创建具体访问者
// 具体访问者 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."); } }
测试代码
public class VisitorTest {
public static void main(String[] args) {
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
System.out.println("------------------------");
ComputerPart mouse = new Mouse();
mouse.accept(new ComputerPartDisplayVisitor());
System.out.println("------------------------");
ComputerPart keyboard = new Keyboard();
keyboard.accept(new ComputerPartDisplayVisitor());
}
}
运行结果
4.扩展
据说访问者模式在开发中使用较为频繁,通常与下面两种设计模式联用
-
迭代器模式:访问者模式中的对象结构是一个包含元素角色的容易,因此我们在遍历容器中的所有元素时,可以使用迭代器模式来提供迭代器
虽然我感觉Java8提供的流处理就好。。。
-
组合模式:访问者模式中的元素对象,可能是叶子对象或者容器对象,如果元素对象是容器对象,那么就必须使用组合模式
后记
据说使用很频繁。。。很。。。频繁吗?
作者:Echo_Ye
WX:Echo_YeZ
Email :echo_yezi@qq.com
个人站点:在搭了在搭了。。。(右键 - 新建文件夹)