一、访问者模式
1、定义
访问者模式(Visitor Pattern)是一种将数据结构与数据操作分离的设计模式,指封装一些作用于某种数据结构中的各元素的操作,可以在不改变数据结构的前提下定义作用于这些元素的新的操作,属于行为型设计模式。
访问者模式的基本思想是,针对系统中拥有固定类型数的对象结构(元素),在其内提供一个 accept()方法来接受访问者对象的访问。不同的访问者对同一个元素的访问内容是不同,使得相同的元素集合可以产生不同的数据结果。
访问者模式又被称为最复杂的设计模式,使用频率不到。因为在开发中,我们很难找到数据结构不变化的情况。
访问者模式的核心是解耦数据结构与数据操作,使得对元素的操作具备优秀的扩展性。
2、结构
(1)模式的结构
主要角色如下:
- 抽象访问者(IVisitor):接口或者抽象类,该类定义了一个 visit()方法用于访问每一个具体的元素,其参数就是具体元素对象。
- 具体访问者(ConcreteVisitor):实现对具体元素的操作。
- 抽象元素(IElement):接口或者抽象类,该类定义了一个接受访问者访问的方法 accept()方法,表示所有元素类型都支持被访问者访问。
- 具体元素(ConcreteElement):具体元素类型,提供接受访问者的具体实现。通常的实现都为 visitor.visit(this)。
- 结构对象(ObjectStructure):该类内部维护了元素集合,并提供方法接受访问者对该集合所有元素进行操作。
3、优缺点
优点:
- 解耦了数据结构与数据操作,使得操作集合可以独立变化。
- 可以通过扩展访问者角色,实现对数据集的不同操作,程序扩展性更好。
- 元素具体类型并非单一,访问者均可操作。
- 各角色职责分离,符合单一职责原则。
缺点:
- 无法增加元素类型,会违背开闭原则。
- 具体元素变更困难,修改的范围很大。
- 违背依赖倒置原则:访问者角色依赖的是具体元素类型,而不是抽象。
4、使用场景
- 数据结构稳定,作用于数据结构的操作经常变化的场景。
- 需要数据结构与数据操作分离的场景。
- 需要对不同数据类型(元素)进行操作,而不使用分支判断具体类型的场景
5、在框架源码中使用
- Java的 NIO模块下的 FileVisitor接口。
- Spring IoC中的 BeanDefinitionVisitor类。
二、模式的通用实现
代码如下:
public class VisitorPattern {
    public static void main(String[] args) {
        ObjectStructure objectStructure = new ObjectStructure();
        IVisitor visitorA = new ConcreteVisitorA();
        objectStructure.showAccept(visitorA);
        System.out.println("====================");
        IVisitor visitorB = new ConcreteVisitorB();
        objectStructure.showAccept(visitorB);
    }
}
// 抽象访问者
interface IVisitor{
    void visit(ConcreteElementA element);
    void visit(ConcreteElementB element);
}
// 具体访问者
class ConcreteVisitorA implements IVisitor{
    @Override
    public void visit(ConcreteElementA element) {
        String result = element.operationA();
        System.out.println("ConcreteVisitorA handler -> result from " + element.getClass().getSimpleName() +", result = " + result);
    }
    @Override
    public void visit(ConcreteElementB element) {
        int result = element.operationB();
        System.out.println("ConcreteVisitorA handler -> result from " + element.getClass().getSimpleName() +", result = " + result);
    }
}
class ConcreteVisitorB implements IVisitor{
    @Override
    public void visit(ConcreteElementA element) {
        String result = element.operationA();
        System.out.println("ConcreteVisitorB handler -> result from " + element.getClass().getSimpleName() +", result = " + result);
    }
    @Override
    public void visit(ConcreteElementB element) {
        int result = element.operationB();
        System.out.println("ConcreteVisitorB handler -> result from " + element.getClass().getSimpleName() +", result = " + result);
    }
}
// 抽象元素
interface IElement{
    void accept(IVisitor visitor);
}
// 具体元素
class ConcreteElementA implements IElement{
    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
    public String operationA(){
        return this.getClass().getSimpleName();
    }
}
class ConcreteElementB implements IElement{
    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
    public int operationB(){
        return new Random().nextInt(100);
    }
}
// 结构对象
class ObjectStructure{
    private List<IElement> list = new ArrayList<>();
    {
        list.add(new ConcreteElementA());
        list.add(new ConcreteElementB());
    }
    // 遍历
    public void showAccept(IVisitor visitor){
        for (IElement element : this.list) {
            element.accept(visitor);
        }
    }
}

三、模式的应用实例
以 KPI考核的场景为例,领导查看员工的 KPI考核。
(1)员工基类 - 抽象元素
public abstract class Employee {
    protected String name;
    //员工 kpi数量
    protected int kpiCount;
    public Employee(String name) {
        this.name = name;
        this.kpiCount = new Random().nextInt(10);
    }
    public abstract void accept(IVisitor visitor);
}
(2)具体元素
public class Manager extends Employee {
	public Manager(String name) {
		super(name);
	}
	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
	// 经理一年的产品量
	public int getProducts() {
		return new Random().nextInt(10);
	}
}
public class Engineer extends Employee{
    public Engineer(String name) {
        super(name);
    }
    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
    //工程师一年的代码量
    public int getCodeLines(){
        return new Random().nextInt(10 * 10000);
    }
}
(3)抽象访问者
public interface IVisitor {
    //访问工程师类型
    void visit(Engineer engineer);
    //访问经理类型
    void visit(Manager manager);
}
(4)具体访问者
// CEO访问者
public class CEOVisitor implements IVisitor{
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程师:" + engineer.name + ",KPI: " + engineer.kpiCount);
    }
    @Override
    public void visit(Manager manager) {
        System.out.println("经理:" + manager.name + ",KPI: " + manager.kpiCount + ",产品数量:" + manager.getProducts());
    }
}
// CTO访问者
public class CTOVisitor implements IVisitor{
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程师:" + engineer.name + ",代码行数: " + engineer.getCodeLines());
    }
    @Override
    public void visit(Manager manager) {
        System.out.println("经理:" + manager.name + ",产品数量: " + manager.getProducts());
    }
}
(5)业务报表类 - 结构对象
public class BusinessReport {
    private List<Employee> employeeList = new ArrayList<>();
    {
        employeeList.add(new Manager("经理A"));
        employeeList.add(new Engineer("Java工程师 - 赵云"));
        employeeList.add(new Engineer("Java工程师 - 后裔"));
        employeeList.add(new Manager("经理B"));
        employeeList.add(new Engineer("Java工程师 - 妲己"));
        employeeList.add(new Engineer("Java工程师 - 露娜"));
    }
    //遍历
    public void showReport(IVisitor visitor){
        for (Employee employee : this.employeeList) {
            employee.accept(visitor);
        }
    }
}
(6)测试
    public static void main(String[] args) {
        BusinessReport businessReport = new BusinessReport();
        System.out.println("=========CEO 看报表==============");
        businessReport.showReport(new CEOVisitor());
        System.out.println("=========CTO 看报表==============");
        businessReport.showReport(new CTOVisitor());
    }

– 求知若饥,虚心若愚。



![[附源码]Python计算机毕业设计服装商城平台Django(程序+LW)](https://img-blog.csdnimg.cn/40e07e03ad5c4628af5f1cdcf0465adb.png)















