0x1、定义
原始定义
允许在 运行时 将一个或多个操作应用于一组对象,将操作与对象结构分离。
简单点说
一组对象,对象结构可以各不相同,但必须以某个或一组操作作为连接的中心点,即:
以行为(某个操作) 作为扩展对象的出发点,在不改变已有类的功能前提下进行批量扩展。
0x2、写个简单例子
以汽车结构为例,里面包含了引擎,车身等,不同角色的人可以对这些结构进行不同的访问,如:
- 司机 → 查看
- 洗车佬 → 清洁
- 维修佬 → 检查维修
不用访问者,代码实现一波:
public abstract class AbstractVisitor { protected String name; public AbstractVisitor(String name) { this.name = name; } abstract void visitorEngine(); abstract void visitorBody(); } public class DriverVisitor extends AbstractVisitor { public DriverVisitor(String name) { super(name); } @Override void visitorEngine() { System.out.println(name + " → 查看引擎"); } @Override void visitorBody() { System.out.println(name + " → 查看车身"); } } public class CleanerVisitor extends AbstractVisitor { public CleanerVisitor(String name) { super(name); } @Override void visitorEngine() { System.out.println(name + " → 清洗引擎"); } @Override void visitorBody() { System.out.println(name + " → 清洗车身"); } } public class RepairVisitor extends AbstractVisitor { public RepairVisitor(String name) { super(name); } @Override void visitorEngine() { System.out.println(name + " → 修理引擎"); } @Override void visitorBody() { System.out.println(name + " → 修理车身"); } } // 测试用例 public class Test { public static void main(String[] args) { List<AbstractVisitor> visitors = new ArrayList<>(); visitors.add(new DriverVisitor("杰哥")); visitors.add(new CleanerVisitor("老王")); visitors.add(new RepairVisitor("大锤")); for(AbstractVisitor visitor: visitors) { visitor.visitorEngine(); visitor.visitorBody(); } } }
代码运行结果如下:
网络异常,图片无法展示
|
可以,但存在问
- 想添加功能,如支持访问轮胎,那么所有类都要改动,违反了开闭原则;
- 访问逻辑都耦合到访问者类中,导致它们的职责不够单一,成了大杂化;
拆分解耦,把业务操作与具体的数据结构解耦,设计成独立的类,用访问者模式对象上述代码重构:
// 抽象访问者 public abstract class AbstractVisitor { protected String name; public AbstractVisitor(String name) { this.name = name; } } // 具体访问者 public class DriverVisitor extends AbstractVisitor { public DriverVisitor(String name) { super(name); } } public class CleanerVisitor extends AbstractVisitor { public CleanerVisitor(String name) { super(name); } } public class RepairVisitor extends AbstractVisitor { public RepairVisitor(String name) { super(name); } } // 对象结构 public class Car { public void visitorEngine(DriverVisitor visitor) { System.out.println(visitor.name + " → 查看引擎"); } public void visitorEngine(CleanerVisitor visitor) { System.out.println(visitor.name + " → 清洗引擎"); } public void visitorEngine(RepairVisitor visitor) { System.out.println(visitor.name + " → 修理引擎"); } public void visitorBody(DriverVisitor visitor) { System.out.println(visitor.name + " → 查看车身"); } public void visitorBody(CleanerVisitor visitor) { System.out.println(visitor.name + " → 清洗车身"); } public void visitorBody(RepairVisitor visitor) { System.out.println(visitor.name + " → 修理车身"); } } // 测试用例 public class Test { public static void main(String[] args) { List<AbstractVisitor> visitors = new ArrayList<>(); visitors.add(new DriverVisitor("杰哥")); visitors.add(new CleanerVisitor("老王")); visitors.add(new RepairVisitor("大锤")); Car car = new Car(); for(AbstractVisitor visitor: visitors) { // 此处编译不通过 car.visitorEngine(visitor); car.visitorBody(visitor); } } }
上述代码理论上是可行,利用函数重载,根据参数类型调用对应方法,实际上却是编译都过不了!
原因是:
Java中的
函数重载
是一种静态绑定
,编译时并不能获取对象的实际类型
,而是根据声明类型
执行声明类型对应的方法。