访问者模式
定义:
- 《设计模式》一书对于访问者模式给出的定义为:表示一个作用于某对象结构中的各元
素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作 - 访问者模式(Vistor Pattern)是一种将数据结构与数据操作分离的的设计模式。
访问者模式适用于数据结构相对稳定, 算法又易变化的系统

组成结构:
  
案例 1
需求:
- 现有一电脑售卖点,电脑是由内存,cpu,和主板三块组成.
- 对于不同来的购买者,内存,cpu,和主板有不同的优惠.
ComputerPart 抽象元素角色
abstract class ComputerPart {
abstract void accept(Visitor v);
abstract double getPrice();
}
CPU、 Memory、 Board 具体元素角色
class CPU extends ComputerPart {
@Override
void accept(Visitor v) {
v.visitCpu(this);
}
@Override
double getPrice() {
return 500;
}
}
class Memory extends ComputerPart {
@Override
void accept(Visitor v) {
v.visitMemory(this);
}
@Override
double getPrice() {
return 300;
}
}
class Board extends ComputerPart {
@Override
void accept(Visitor v) {
v.visitBoard(this);
}
@Override
double getPrice() {
return 200;
}
}
Computer 对象结构角色
class Computer {
ComputerPart cpu = new CPU();
ComputerPart memory = new Memory();
ComputerPart board = new Board();
public void acccept(Visitor v) {
this.cpu.accept(v);
this.memory.accept(v);
this.board.accept(v);
}
}
Visitor 抽象访问中角色
interface Visitor {
void visitCpu(CPU cpu);
void visitMemory(Memory memory);
void visitBoard(Board board);
}
PersonelVisitor 、CorpVisitor 具体访问者 角色
class PersonelVisitor implements Visitor {
double totalPrice = 0.0;
@Override
public void visitCpu(CPU cpu) {
totalPrice += cpu.getPrice()*0.9;
}
@Override
public void visitMemory(Memory memory) {
totalPrice += memory.getPrice()*0.85;
}
@Override
public void visitBoard(Board board) {
totalPrice += board.getPrice()*0.95;
}
}
class CorpVisitor implements Visitor {
double totalPrice = 0.0;
@Override
public void visitCpu(CPU cpu) {
totalPrice += cpu.getPrice()*0.6;
}
@Override
public void visitMemory(Memory memory) {
totalPrice += memory.getPrice()*0.75;
}
@Override
public void visitBoard(Board board) {
totalPrice += board.getPrice()*0.75;
}
}
测绘类
public class Main {
public static void main(String[] args) {
PersonelVisitor p = new PersonelVisitor();
new Computer().acccept(p);
System.out.println("PersonelVisitor: "+p.totalPrice);
}
}

双重分派 
案例 2 编译器
抽象语法树:

传统编程模式 :

访问者模式:

访问者模式运用最多,就是在做编译器的时候
总结:
使用场景:
- 数据结构要稳定,但是作用于数据结构上的操作经常变化 (如上面示例中如果元素价格经常发生变化,那么每次变化都要修改访问者对象)。
- 需要对不同数据类型(元素)进行操作,而不使用分支判断具体类型的场景。
优点:
- 符合单一职责原则
- 访问者角色非常易于扩展
- 解耦了数据结构和数据操作,使得操作集合可以独立变化
缺点:
- 具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的
- 具体元素变更比较困难
- 违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素
应用:
- 访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。
- 访问者模式适用于数据结构相对稳定的系统
|