访问者模式相对来说比较抽象和难以理解,可能单纯地通过文字、类图、案例代码大家还是不太容易理解该模式,不过希望大家不要急躁,可以静下心来用心的体会该设计模式的魅力。相信你一定会有所收获。
基本介绍
访问者模式的基本概念:封装一些作用于某种数据结构中元素上的操作。其有一个重要的特征是可以在不改变数据结构的前提下定义一些新的操作。
简单来说访问者模式主要的作用就是将“数据结构”和“数据操作”进行分离,解决这两者之间耦合性的问题。
访问者模式的基本执行原理就是在被访问的类里添加一个接口,用于接待访问者。
一般数情况下,当我们需要对一个数据结构中的元素进行很多不同的操作,并且这些操作彼此之间并没有关联,同时我们还想做到避免因为这些操作而“污染”了这些元素时,就可考虑使用访问者模式。
访问者模式UML类图
类图讲解
Visitor:抽象访问角色;通常情况下该数据结构中有几个元素就会对应的在该类中为每一个元素提供一个访问操作(方法)。
ConcreteVisitor:具体访问者角色;继承了Visitor并实现了其中定义的所以方法。
Element:抽象元素角色;该类会定义一个accept(接收)方法,用于接收访问者。
ConcreteElement:具体元素角色;继承了Element并实现了其中定义的accept方法。
ObjectStruture:该类定义了数据结构(对象结构),管理了所有元素,并且可以枚举它的元素(也就是遍历)。
案例讲解
案例:开发一个员工审批功能,具体为不同角色的员工可以进行“同意”和“不同意”的审批。
抽象员工类 => 对应Element(抽象元素角色)
- public abstract class Workers {
- // 提供一个让访问者访问的方法
- public abstract void accept(Action action);
- }
具体员工类
- /**
- * 经理
- */
- public class Manager extends Workers {
- /**
- * 这里用到了双分派。
- * 第一次分派:在客户端中将具体的Action作为参数传递到Manager中。
- * 第二次分派:Manager类调用Action中的具体方法,并将自己作为参数传入。
- */
- @Override
- public void accept(Action action) {
- action.managerVerify(this);
- }
- }
- /**
- * 组长
- */
- public class GroupLeader extends Workers {
- @Override
- public void accept(Action action) {
- action.groupLeaderVerify(this);
- }
- }
抽象行为类 => 对应Visitor(抽象访问角色)
- public abstract class Action {
- // 经理进行审批
- public abstract void managerVerify(Manager manager);
- // 组长进行审批
- public abstract void groupLeaderVerify(GroupLeader groupLeader);
- }
具体行为类
- /**
- * 同意
- */
- public class Agree extends Action {
- @Override
- public void managerVerify(Manager manager) {
- System.out.println("经理的审核结果为同意!");
- }
- @Override
- public void groupLeaderVerify(GroupLeader groupLeader) {
- System.out.println("组长的审核结果为同意!");
- }
- }
- /**
- * 不同意
- */
- public class Disagree extends Action {
- @Override
- public void managerVerify(Manager manager) {
- System.out.println("经理的审核结果为不同意!");
- }
- @Override
- public void groupLeaderVerify(GroupLeader groupLeader) {
- System.out.println("组长的审核结果为不同意!");
- }
- }
ObjectStructure类
- public class ObjectStructure {
- // 维护了一个集合
- private List<Workers> peoples = new ArrayList<>();
- // 增加
- public void attach(Workers workers) {
- peoples.add(workers);
- }
- // 移除
- public void detach(Workers workers) {
- peoples.remove(workers);
- }
- // 显示测评情况
- public void display(Action action) {
- for (Workers people : peoples) {
- people.accept(action);
- }
- }
- }
客户端测试类
- public class Client {
- public static void main(String[] args) {
- ObjectStructure objectStructure = new ObjectStructure();
- // 添加人
- objectStructure.attach(new Manager());
- objectStructure.attach(new GroupLeader());
- // 同意
- Agree agree = new Agree();
- objectStructure.display(agree);
- }
- }
执行结果
总结
优点:
1、访问者模式符合单一职责原则。
2、可以让数据结构和数据操作之间解耦。
3、避免了因为操作元素而对其造成污染的问题。
4、让程序具有扩展性的情况下还大大增加了灵活性。
缺点:
1、因为具体的元素对访问者公布了实现细节,所以访问者模式是违背了迪米特法则的。这样做会导致元素变化比较困难。
2、因为访问者依赖的是具体的元素而不是其抽象父类,所有该模式还违背了依赖倒转原则。
总结 :访问者模式适用于数据结构相对稳定并且功能需求还经常变化的系统。