本文最后更新于:3 years ago
在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于 行为型模式 。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
如果想了解访问者模式的具体的介绍,菜鸟教程介绍得比较详细↓
菜鸟教程-访问者模式
结构图
优缺点
优点:
1、符合单一职责原则。
2、优秀的扩展性。
3、灵活性。
缺点:
1、具体元素对访问者公布细节,违反了迪米特原则。
2、具体元素变更比较困难。
3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
使用场景
1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作”污染”这些对象的类,也不希望在增加新操作时修改这些类。
实现代码
模拟一个场景,外设店中的一套外设配置(键盘+鼠标+显示屏),不同的人去购买的这套外设厂家所给与的折扣是不一样的,对于学生的折扣比个人去购买折扣会大很多。并且购买这套配置的话,键盘、鼠标、显示器的折扣是不一样的
首先定义一个ComputerPart抽象类,这里我们将创建两个方法,accept和getPrice
| abstract class ComputerPart { abstract void accept(Visitor v); abstract double getPrice(); }
|
accept()用于接收访问者,当你调用我这个方法时,需要你传入一个Visitor的对象,而这个Visitor对象已经实现了相应的方法(visitKeyboard、visitMouse、visitMonitor)
getPrice用于查看对于用户这个类(Student)打完折扣后总价为多少
接着创建Keyboard、Mouse、Monitor三个类,继承ComputerPart类,重写上面的两个类,
| class Keyboard extends ComputerPart {
@Override void accept(Visitor v) { v.visitKeyboard(this); }
@Override double getPrice() { return 1000; } }
|
对于accept对象,对于传入的Visitor对象,我们调用已经由Visitor对象自己实现的visitKeyboard()方法(Mouse、Monitor同),实现重写;getPrice我们返回外设的原价
创建一个Visitor接口,接口中创建三个类,由子类自己实现这些方法
| interface Visitor { void visitKeyboard(Keyboard keyboard);
void visitMouse(Mouse mouse);
void visitMonitor(Monitor monitor); }
|
调用者自己实现相应的折扣,并返回总价
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class StudentVisitor implements Visitor { double totalPrice = 0.0;
@Override public void visitKeyboard(Keyboard keyboard) { totalPrice += keyboard.getPrice() * 0.8; }
@Override public void visitMouse(Mouse mouse) { totalPrice += mouse.getPrice() * 0.85; }
@Override public void visitMonitor(Monitor monitor) { totalPrice += monitor.getPrice() * 0.85; } }
|
代码如下:
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
| public class Main { public static void main(String[] args) { StudentVisitor student = new StudentVisitor(); new Computer().accept(student); System.out.println(student.totalPrice); }
}
class Computer { ComputerPart keyboard = new Keyboard(); ComputerPart mouse = new Mouse(); ComputerPart monitor = new Monitor();
public void accept(Visitor v) { this.keyboard.accept(v); this.mouse.accept(v); this.monitor.accept(v); } }
abstract class ComputerPart { abstract void accept(Visitor v); abstract double getPrice(); }
class Keyboard extends ComputerPart {
@Override void accept(Visitor v) { v.visitKeyboard(this); }
@Override double getPrice() { return 1000; } }
class Mouse extends ComputerPart {
@Override void accept(Visitor v) { v.visitMouse(this); }
@Override double getPrice() { return 800; } }
class Monitor extends ComputerPart {
@Override void accept(Visitor v) { v.visitMonitor(this); }
@Override double getPrice() { return 1200; } }
interface Visitor { void visitKeyboard(Keyboard keyboard);
void visitMouse(Mouse mouse);
void visitMonitor(Monitor monitor); }
class StudentVisitor implements Visitor { double totalPrice = 0.0;
@Override public void visitKeyboard(Keyboard keyboard) { totalPrice += keyboard.getPrice() * 0.8; }
@Override public void visitMouse(Mouse mouse) { totalPrice += mouse.getPrice() * 0.85; }
@Override public void visitMonitor(Monitor monitor) { totalPrice += monitor.getPrice() * 0.85; } }
class PersonVisitor implements Visitor { double totalPrice = 0.0;
@Override public void visitKeyboard(Keyboard keyboard) { totalPrice += keyboard.getPrice() * 0.9; }
@Override public void visitMouse(Mouse mouse) { totalPrice += mouse.getPrice() * 0.95; }
@Override public void visitMonitor(Monitor monitor) { totalPrice += monitor.getPrice() * 0.95; } }
|
输出结果:
Visitor模式结构是固定死的,你是不能改的,能改的也只有变化数据操作上(StudentVisitor、PersonVisitor)。所以当内部结构固定的情况下可以用Visitor模式
Visitor模式用的不多,这个模式用的地方比较窄,主要用在语言编辑器这方面(这个方向用的比较多)了解即可。