访问者模式
访问者(Visitor)模式的定义:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离,是行为类模式中最复杂的一种模式。
UML结构图
- Vistor:抽象访问者,定义一个访问具体元素的接口,声明了对 ConcreteElement 类的一些操作
- ConcreteVisitor:具体访问者,实现抽象访问者角色中声明的各个访问操作,
- Element:抽象元素,定义一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
- ConcreteElement:具体元素 ,实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
- ObjectStructure:对象结构,是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法。
代码实现
抽象访问者 Visitor .class
package com.lq.visitor;
/**
* @author lq
* @PACKAGE_NAME: com.lq.visitor
* @CLASS_NAME: Visitor
* @date 2022/11/9 22:56
* @Description: 抽象访问者,定义一个访问具体元素的接口,声明了对 ConcreteElement 类的一些操作
*/
public interface Visitor {
void visitCpu(CPU cpu);
void visitBoard(Board board);
}
具体访问者
package com.lq.visitor;
/**
* @author lq
* @PACKAGE_NAME: com.lq.visitor
* @CLASS_NAME: PersonelVisitor
* @date 2022/11/9 22:56
* @Description: 具体访问者,实现抽象访问者角色中声明的各个访问操作,
*/
public class PersionlVisitor implements Visitor{
double totalPrice = 0.0;
@Override
public void visitCpu(CPU cpu) {
totalPrice += cpu.getPrice()*0.9;
}
@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 visitBoard(Board board) {
totalPrice += board.getPrice()*0.75;
}
}
抽象元素 ComputerPart .class
package com.lq.visitor;
/**
* @author lq
* @PACKAGE_NAME: com.lq.visitor
* @CLASS_NAME: ComputerPart
* @date 2022/11/9 22:54
* @Description: 抽象元素,定义一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
*/
public abstract class ComputerPart {
abstract void accept(Visitor v);
abstract double getPrice();
}
具体元素
package com.lq.visitor;
/**
* @author lq
* @PACKAGE_NAME: com.lq.visitor
* @CLASS_NAME: Board
* @date 2022/11/9 22:56
* @Description: 具体元素 ,实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
*/
public class Board extends ComputerPart{
@Override
void accept(Visitor v) {
v.visitBoard(this);
}
@Override
double getPrice() {
return 200;
}
}
class CPU extends ComputerPart{
@Override
void accept(Visitor v) {
v.visitCpu(this);
}
@Override
double getPrice() {
return 500;
}
}
对象结构
package com.lq.visitor;
/**
* @author lq
* @PACKAGE_NAME: com.lq.visitor
* @CLASS_NAME: Computer
* @date 2022/11/9 22:55
* @Description: 对象结构,是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法
*/
public class Computer {
ComputerPart cpu = new CPU();
ComputerPart board = new Board();
public void accept(Visitor v) {
this.cpu.accept(v);
this.board.accept(v);
}
}
测试
package com.lq.visitor;
/**
* @author lq
* @PACKAGE_NAME: com.lq.visitor
* @CLASS_NAME: Main
* @date 2022/11/9 22:57
* @Description:
*/
public class Main {
public static void main(String[] args) {
PersionlVisitor p = new PersionlVisitor();
new Computer().accept(p);
System.out.println(p.totalPrice);
}
}
结果
640.0
优点
- 扩展性好。能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
- 复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
- 灵活性好。访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
- 符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。
缺点
- 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
- 破坏封装。访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性。
- 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类。