Visitor design pattern is one of the behavioral design patterns. It is used when we have to perform an operation on a group of similar kind of Objects. With the help of visitor pattern, we can move the operational logic from the objects to another class.
前言 访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
访问者模式 基本介绍:
1) 访问者模式(Visitor Pattern ),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作; 2) 主要将数据结构与数据操作分离,解决 数 据结构和 操 作耦 合 性问题; 3) 访问者模 式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口; 4) 访问者模 式 主 要应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作”污染”这些对象的类,可以选用访问者模式解决。
角色介绍:
Visitor: 接口或者抽象类,定义了对每个 Element 访问的行为,它的参数就是被访问的元素,它的方法个数理论上与元素的个数是一样的,因此,访问者模式要求元素的类型要稳定,如果经常添加、移除元素类,必然会导致频繁地修改 Visitor 接口,如果出现这种情况,则说明不适合使用访问者模式。 ConcreteVisitor: 具体的访问者,它需要给出对每一个元素类访问时所产生的具体行为。 Element: 元素接口或者抽象类,它定义了一个接受访问者(accept)的方法,其意义是指每一个元素都要可以被访问者访问。 ElementA、ElementB: 具体的元素类,它提供接受访问的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。 ObjectStructure: 定义当中所提到的对象结构,对象结构是一个抽象表述,它内部管理了元素集合,并且可以迭代这些元素提供访问者访问。
访问者模式-UML图:
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 import java.util.LinkedList;import java.util.List;import java.util.Random;public class Vistitor { public static void main (String[] args) { BusinessReport report = new BusinessReport(); System.out.println("=========== CEO看报表 ===========" ); report.showReport(new CEOVisitor()); System.out.println("=========== CTO看报表 ===========" ); report.showReport(new CTOVisitor()); } } abstract class Staff { public String name; public int kpi; public Staff (String name) { this .name = name; kpi = new Random().nextInt(10 ); } public abstract void accept (Visitor visitor) ; } class Engineer extends Staff { public Engineer (String name) { super (name); } @Override public void accept (Visitor visitor) { visitor.visit(this ); } public int getCodeLines () { return new Random().nextInt(10 * 10000 ); } } class Manager extends Staff { public Manager (String name) { super (name); } @Override public void accept (Visitor visitor) { visitor.visit(this ); } public int getProducts () { return new Random().nextInt(10 ); } } interface Visitor { void visit (Engineer engineer) ; void visit (Manager manager) ; } class BusinessReport { private List<Staff> mStaffs = new LinkedList<>(); public BusinessReport () { mStaffs.add(new Manager("经理-A" )); mStaffs.add(new Engineer("工程师-A" )); mStaffs.add(new Engineer("工程师-B" )); mStaffs.add(new Engineer("工程师-C" )); mStaffs.add(new Manager("经理-B" )); mStaffs.add(new Engineer("工程师-D" )); } public void showReport (Visitor visitor) { for (Staff staff : mStaffs) { staff.accept(visitor); } } } class CEOVisitor implements Visitor { @Override public void visit (Engineer engineer) { System.out.println("工程师: " + engineer.name + ", KPI: " + engineer.kpi); } @Override public void visit (Manager manager) { System.out.println("经理: " + manager.name + ", KPI: " + manager.kpi + ", 新产品数量: " + manager.getProducts()); } } class ReportUtil { public void visit (Staff staff) { if (staff instanceof Manager) { Manager manager = (Manager) staff; System.out.println("经理: " + manager.name + ", KPI: " + manager.kpi + ", 新产品数量: " + manager.getProducts()); } else if (staff instanceof Engineer) { Engineer engineer = (Engineer) staff; System.out.println("工程师: " + engineer.name + ", KPI: " + engineer.kpi); } } } class CTOVisitor implements Visitor { @Override public void visit (Engineer engineer) { System.out.println("工程师: " + engineer.name + ", 代码行数: " + engineer.getCodeLines()); } @Override public void visit (Manager manager) { System.out.println("经理: " + manager.name + ", 产品数量: " + manager.getProducts()); } }
总结 访问者模式的注意事项和细节:
优点
1) 访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高; 2) 访问者模式可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统。
缺点
1) 具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的, 这样造成了具体元素变更比较困难; 2) 违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素; 3) 因此,如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问 者模式就是比较合适的。
延伸 访问者模式一篇就够了 访问者模式-菜鸟教程 Visitor design pattern Design Patterns - Visitor Pattern 尚硅谷Java设计模式,韩顺平图解java设计模式