20.访问者模式

一、介绍

  1. 访问者模式的目的是封装一些施加于某种数据结构元素之上的操作,一旦这些操作需要修改,接受这个操作的数据结构则可以保持不变;
  2. 封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

二、原理类图

1

2.1 角色与职责

  1. 抽象访问者(Visitor)角色:该角色声明一个或多个访问操作,定义访问者可以访问哪些元素。
  2. 具体访问者(Concrete Visitor)角色:该角色实现抽象访问者角色中的各个访问操作。
  3. 抽象元素(Element)角色:该角色声明一个接受操作,接受一个访问者对象。
  4. 具体元素(Concrete Element)角色:该角色实现抽象元素中的接受操作。
  5. 结构对象(Object Structure)角色:该角色有以下责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素,也可以设计一个复合对象或者一个集合,如List或Set。

2.2 代码实例分析

使用访问者模式完成对计算机中各种硬件的访问。类图如图所示:

1

  1. Hardware抽象类代表计算机的各种硬件,对应访问模式中的抽象元素角色,其代码如下所示。
    【描述6.D.4】 Hardware.java
public abstract class Hardware {
     String type; // 型号
     public Hardware(String type) {
         this.type = type;
     }
     public String getType() {
         return type;
     }
     // 运转
     public abstract void run();
     // 接受计算机访问者
     public abstract void accept(ComputerVisitor computerVisitor);
 }
  1. ComputerVisitor接口代表对计算机硬件的访问者,代码如下所示。
    【描述6.D.4】 ComputerVisitor.java
public interface ComputerVisitor {
    void vistCPU(CPU cpu); // 访问CPU
    void vistHarddisk(Harddisk harddisk); // 访问硬盘
}
  1. CPU类和Harddisk类分别代表计算机的CPU和硬盘,是两个硬件,都继承Hardware抽象类。代码分别如下所示。
    【描述6.D.4】 CPU.java
public class CPU extends Hardware {
    public CPU(String type) {
        super(type);
    }
    @Override
    public void run() {
        System.out.println("型号为" + type + "的CPU正在运转");
    }
    @Override
    public void accept(ComputerVisitor computerVisitor) {
        computerVisitor.vistCPU(this);
    }
}

【描述6.D.4】 Harddisk.java

public class Harddisk extends Hardware {
    public Harddisk(String type) {
        super(type);
    }
    @Override
    public void run() {
        System.out.println("型号为" + type + "的硬盘正在运转");
    }
    @Override
    public void accept(ComputerVisitor computerVisitor) {
        computerVisitor.vistHarddisk(this);
    }
}
  1. TypeVisitor类代表对计算机硬件型号的访问者,代码如下。
    【描述6.D.4】 TypeVisitor.java
public class TypeVisitor implements ComputerVisitor {
    @Override
    public void vistCPU(CPU cpu) {
        System.out.println("CPU型号:" + cpu.getType());
    }
    @Override
    public void vistHarddisk(Harddisk harddisk) {
        System.out.println("硬盘型号:" + harddisk.getType());
    }
}
  1. RunVisitor类代表使计算机硬件运转的访问者,代码如下。
    【描述6.D.4】 RunVisitor.java
public class RunVisitor implements ComputerVisitor {
    @Override
    public void vistCPU(CPU cpu) {
        cpu.run();
    }
    @Override
    public void vistHarddisk(Harddisk harddisk) {
        harddisk.run();
    }
}
  1. Computer类代表计算机,由CPU和硬盘组成,对应访问者模式中的结构对象角色,其代码如下所示。
    【描述6.D.4】 Computer.java
public class Computer {
     private Hardware cpu;
     private Hardware harddisk;
     public Computer(){
         this.cpu = new CPU("Intel Core i7-620");
         this.harddisk = new Harddisk("Seagate 500G 7200转");
     }
     public void accept(ComputerVisitor computerVisitor) {
         cpu.accept(computerVisitor);
         harddisk.accept(computerVisitor);
     }
 }
  1. 应用类ClientDemo的代码如下。
    【描述6.D.4】 ClientDemo.java
public class ClientDemo {
    public static void main(String[] args) {
        Computer computer = new Computer();
        ComputerVisitor typeVisitor = new TypeVisitor();
        ComputerVisitor runVisitor = new RunVisitor();
        computer.accept(typeVisitor);
        System.out.println("-----------------");
        computer.accept(runVisitor);
    }
}
  1. 运行结果如下:
	CPU型号:Intel Core i7-620
    硬盘型号:Seagate 500G 7200-----------------
    型号为Intel Core i7-620的CPU正在运转
    型号为Seagate 500G 7200转的硬盘正在运转

三、优缺点

3.1 优点

  1. 访问者模式使得增加新的操作变得很容易,增加新的操作只需要增加新的访问者类。
  2. 访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个元素类中。
  3. 访问者模式可以跨过几个类的等级结构访问属于不同等级结构的成员类。
  4. 累积状态。每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中将执行操作的状态积累在自己内部,而不是分散到很多的元素对象中,益于系统的维护。

3.2 缺点

  1. 增加新的元素类变得很困难:每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作。
  2. 破坏封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,这隐含了一个对所有元素对象的要求,即必须暴露一些自己的操作和内部状态,否则访问者的访问就变得没有意义。由于访问者对象自己会积累访问操作所需的状态,从而使得这些状态不再存储在元素对象中,破坏了类的封装性。
  3. 违背了依赖倒置原则。访问者依赖的是具体的元素,而不是抽象的元素,这破坏了依赖倒置的原则,特别是在面向对象的编程中,抛弃了对接口的依赖,而直接依赖实现类,扩展比较难。

四、应用场景

  1. 一个对象结构包含很多类对象,它们有不同的接口,当对这些对象实施依赖于具体类的操作时,即使用迭代器模式不能胜任的场景下,可以采用访问者模式。
  2. 需要对一个对象结构中的对象进行很多不同并且不相关的操作,避免操作污染类。
  3. 业务规则要求遍历多个不同的对象,这本身也是访问者模式的出发点,迭代器模式只能访问同类或同接口的数据,而访问者模式是对迭代器模式的扩充,可以遍历不同的对象,执行不同的操作。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值