# 访问者模式(Visitor Pattern)

目录: https://note.dolyw.com/design/ (opens new window)

代码地址

# 1. 介绍

访问者模式中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作

# 1.1. 特点

待补充

# 1.2. 结构

  • 抽象节点(Node):声明一个接受操作,接受一个访问者对象作为一个参数
  • 具体节点(ConcreteNode):实现了抽象节点所规定的接受操作
  • 结构对象(ObjectStructure):也可以同时充当节点的作用,有如下的责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如 List 或 Set
  • 抽象访问者(Visitor):声明了一个或者多个方法操作,形成所有的具体访问者角色必须实现的接口
  • 具体访问者(ConcreteVisitor):实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作

# 1.3. 优缺点

  • 意图:主要将数据结构与数据操作分离
  • 主要解决:稳定的数据结构和易变的操作耦合问题
  • 何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中
  • 如何解决:在被访问的类里面加一个对外提供接待访问者的接口
  • 关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者
  • 使用场景:
    • 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作
    • 节点是固定的,访问者根据本身的情况去实现节点扩展的功能
  • 优点:
    • 符合单一职责原则
    • 优秀的扩展性
    • 灵活性
  • 缺点:
    • 具体元素对访问者公布细节,违反了迪米特原则
    • 具体元素变更比较困难
    • 违反了依赖倒置原则,依赖了具体类,没有依赖抽象
  • 应用实例:根据购买物品的访问者,来进行实现折扣,物品是不变的,变的是访问者,折扣的实现在访问者处理,这就是访问者模式 注意事项:访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器

# 2. 代码

使用一个购买组装电脑各种零件,对个人及公司访问者不同优惠的例子

# 2.1. Node

/**
 * 计算机抽象节点
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/2/3 17:33
 */
public abstract class ComputerNode {

    public abstract void accept(Visitor visitor);

    /**
     * 原始价格
     * @return
     */
    public double getPrice() {
        return 0;
    }
}

# 2.1. ConcreteNode

/**
 * 计算机CPU具体节点
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/2/3 17:33
 */
public class CpuComputerNodeImpl extends ComputerNode {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    @Override
    public double getPrice() {
        return 1500;
    }
}
/**
 * 计算机内存条具体节点
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/2/3 17:33
 */
public class MemoryComputerNodeImpl extends ComputerNode {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    @Override
    public double getPrice() {
        return 500;
    }
}
/**
 * 计算机主板具体节点
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/2/3 17:33
 */
public class BoardComputerNodeImpl extends ComputerNode {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    @Override
    public double getPrice() {
        return 1000;
    }
}

# 2.2. ObjectStructure

/**
 * 计算机结构对象,也可以同时充当具体节点的作用
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/2/3 17:33
 */
public class ComputerStructure extends ComputerNode {

    /*ComputerNode computerNode = new CpuComputerNodeImpl();
    ComputerNode memoryComputerNode = new MemoryComputerNodeImpl();
    ComputerNode boardComputerNode = new BoardComputerNodeImpl();*/

    protected ComputerNode[] computerNodeArray;

    public ComputerStructure() {
        computerNodeArray = new ComputerNode[] {new CpuComputerNodeImpl(),
                new MemoryComputerNodeImpl(), new BoardComputerNodeImpl()};
    }

    @Override
    public void accept(Visitor visitor) {
        /*this.computerNode.accept(visitor);
        this.memoryComputerNode.accept(visitor);
        this.boardComputerNode.accept(visitor);*/
        for (ComputerNode computerNode : computerNodeArray) {
            computerNode.accept(visitor);
        }
        // 整个结构对象,也同时充当节点的作用就需要调用
        visitor.visit(this);
    }

    @Override
    public double getPrice() {
        // 计算机除去CPU内存主板后其他东西的总和
        return 1000;
    }
}

# 2.3. Visitor

/**
 * 访问者接口
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/2/3 17:33
 */
public interface Visitor {

    void visit(CpuComputerNodeImpl cpuComputerNode);

    void visit(MemoryComputerNodeImpl memoryComputerNode);

    void visit(BoardComputerNodeImpl boardComputerNode);

    void visit(ComputerStructure computerStructure);
}

# 2.4. ConcreteVisitor

/**
 * 个人访问者,CPU 95折,内存8折,主板9折,其他8折
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/2/3 17:33
 */
public class PersonelVisitorImpl implements Visitor {

    private double totalPrice = 0.0;

    @Override
    public void visit(CpuComputerNodeImpl cpuComputerNode) {
        totalPrice = totalPrice + cpuComputerNode.getPrice() * 0.95;
    }

    @Override
    public void visit(MemoryComputerNodeImpl memoryComputerNode) {
        totalPrice = totalPrice + memoryComputerNode.getPrice() * 0.8;
    }

    @Override
    public void visit(BoardComputerNodeImpl boardComputerNode) {
        totalPrice = totalPrice + boardComputerNode.getPrice()* 0.9;
    }

    /**
     * 计算机除去CPU内存主板后其他东西的总和
     *
     * @param computerStructure
     */
    public void visit(ComputerStructure computerStructure) {
        totalPrice = totalPrice * 0.8;
    }

    public double getTotalPrice() {
        return totalPrice;
    }
}
/**
 * 公司访问者,CPU 85折,内存7折,主板8折,其他6折
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/2/3 17:33
 */
public class CorpVisitorImpl implements Visitor {

    private double totalPrice = 0.0;

    @Override
    public void visit(CpuComputerNodeImpl cpuComputerNode) {
        totalPrice = totalPrice + cpuComputerNode.getPrice() * 0.85;
    }

    @Override
    public void visit(MemoryComputerNodeImpl memoryComputerNode) {
        totalPrice = totalPrice + memoryComputerNode.getPrice() * 0.7;
    }

    @Override
    public void visit(BoardComputerNodeImpl boardComputerNode) {
        totalPrice = totalPrice + boardComputerNode.getPrice() * 0.8;
    }

    /**
     * 总结点本身触发
     *
     * @param computerStructure
     */
    public void visit(ComputerStructure computerStructure) {
        totalPrice = totalPrice * 0.6;
    }

    public double getTotalPrice() {
        return totalPrice;
    }
}

# 2.5. Main

/**
 * 访问者模式,一个购买组装电脑各种零件,对个人及公司访问者不同优惠的例子
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/2/3 17:33
 */
public class Main {

    public static void main(String[] args) {
        // 整个结构对象,也同时充当节点的作用
        ComputerStructure computerStructure = new ComputerStructure();
        // 个人购买
        PersonelVisitorImpl personelVisitor = new PersonelVisitorImpl();
        computerStructure.accept(personelVisitor);
        System.out.println(personelVisitor.getTotalPrice());
        // 公司购买
        CorpVisitorImpl corpVisitor = new CorpVisitorImpl();
        computerStructure.accept(corpVisitor);
        System.out.println(corpVisitor.getTotalPrice());
    }
}
2180.0
1455.0
上次更新时间: 2023-12-15 03:14:55