基本需求:
- 电脑需要键盘鼠标等固定的组件组成
- 现在分为个人,组织等去买电脑,而同一种组件对不同的人(访问者)做出不同的折扣,从而电脑的价格也不一样
- 传统的解决方法:在组件内部进行判断访问人的类型,从而进行不同打出不同的折扣
基本介绍:
-
在访问者模式(Visitor)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作
-
也就是说,被访问者可以根据不同的访问者做出不同的响应
-
封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作
-
主要将数据结构与数据操作分离,解决 数据结构和操作耦合性问题
-
访问者模式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口
-
访问者模式主要应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以选用访问者模式解决
-
UML类图(原理)
-
-
说明
- Visitor是抽象访问者,为该对象结构中的ConcreteElement的每一个类声明一个visit操作
- ConcreteVisitor是一个具体的访问值实现每个有Visitor声明的操作,是每个操作实现的部分
- ObjectStructure能枚举它的元素,可以提供一个高层的接口,用来允许访问者访问元素
- Element定义一个accept 方法,接收一个访问者对象
- ConcreteElement为具体元素,实现了accept方法
- 核心思想就是:不同访问者通过accept访问相同的被访问者,被访问者根据访问者携带的方法做出具体的动作,从而达到相同的被访问者再不同的场景下做出不同的响应,对被访问者没有任何影响,也就是双分派
-
-
UML类图(案例)
-
代码实现
-
public abstract class ComputerPart { // 电脑组件抽象父类 也就是被访问者 提供接收访问者方法 protected String name; protected double price; public ComputerPart(String name,double price) { this.name = name; this.price = price; } // 接收访问者,双分派中第一次分派 public abstract double accept(Visitor visitor); } // 子类一 class Keyboard extends ComputerPart{ public Keyboard(String name,double price) { super(name,price); } @Override public double accept(Visitor visitor) { // 调用访问者的访问回调方法,将自身再传递给访问者,第二次分派,对不同的访问者做出不同的响应 // 这个this是关键,也是重点 return visitor.visitKeyboard(this); } } // 子类二 class Mouse extends ComputerPart{ public Mouse(String name,price); } @Override public double accept(Visitor visitor) { // 调用访问者的访问回调方法,将自身再传递给访问者,第二次分派,对不同的访问者做出不同的响应 // 这个this是关键,也是重点 return visitor.visitMouse(this); } }
-
public interface Visitor { // 访问者抽象父接口 其中的访问回调方法(参数为具体的被访问者)需要包含所有的访问者实现 // 所以这就要求了被访问的子类是固定的,如果不固定,增加或者删除,就要修改Visitor类中方法数量 // 访问Keyboard的访问回调 这样不同的访问者访问同一个被访问者得到的结果都不同 double visitKeyboard(Keyboard keyboard); // 访问Mouse的访问回调 double visitMouse(Mouse mouse); } // 子类一 个人用户 为方便都是九折 class PersonVisitor implements Visitor { @Override public double visitKeyboard(Keyboard keyboard) { return keyboard.price * 0.9; } @Override public double visitMouse(Mouse mouse) { return mouse.price * 0.9; } } // 子类二 群体用户 为方便都是八折 class GroupVisitor implements Visitor { @Override public double visitKeyboard(Keyboard keyboard) { return keyboard.price * 0.8; } @Override public double visitMouse(Mouse mouse) { return mouse.price * 0.8; } }
-
public class Computer { // 此类作为 ObjectStructure,聚合了被访问者并使用 private Keyboard keyboard; private Mouse mouse; public Computer(Keyboard keyboard,Mouse mouse) { this.keyboard = keyboard; this.mouse = mouse; } // 根据不同的访问者获取电脑的价格 public double getPrice(Visitor visitor) { // 被访问者就收访问者 return keyboard.accept(visitor) + mouse.accept(visitor); } }
-
public class Client { public static void main(String[] args) { // 创建鼠标键盘和电脑 Keyboard keyboard = new Keyboard("keyboard",100d); Mouse mouse = new Mouse("mouse",100d); Computer computer = new Computer(keyboard,mouse); // 使用不同的访问者获取电脑的价格 PersonVisitor personVisitor = new PersonVisitor(); System.out.println("个人获得的电脑价格是:" + computer.getPrice(personVisitor)); GroupVisitor groupVisitor = new GroupVisitor(); System.out.println("群体获得的电脑价格是:" + computer.getPrice(groupVisitor)); // 如果还有其他的访问者,直接增加其实现类即可,不用改动其他代码,被访问者就可以做出不同的响应 } }
-