定义

访问者模式是对象的行为型模式,它的目的是封装一些施加于某些数据结构元素之上的操作,一旦这些操作需要修改的话,接收这个操作的数据结构则可以保持不变

意图

将数据结构与数据操作分离

解决问题

稳定的数据结构和易变的操作耦合问题

何时使用

要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中

优缺点

优点:

  • 使得增加新的操作很容易
  • 将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中
  • 可以跨过几个类的等级结构访问属于不同的等级结构的成员类

缺点:

  • 增加新的节点类变的很困难
  • 破坏封装

结构



涉及的角色:

  • 抽象访问者(Visitor)角色:声明了一个或者多个访问操作,形成所有的具体元素角色必须实现的接口
  • 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口,也就是抽象访问者所声明的各个访问操作
  • 抽象节点(Node)角色:声明一个接收操作,接收一个访问者对象作为一个参量
  • 具体节点(Node)角色:实现了抽象节点所规定的接收操作
  • 结构对象(ObjectStructure)角色:有下面的一些职责,可以遍历结构中的所有元素,如果需要,提供一个高层次接口让访问者对象可以访问每一个元素,如果需要,可以设计一个复合对象或者聚集,比如list或set

源码如下:

抽象访问者角色为每一个节点都提供了一个访问操作,并且接收相应的节点对象作为参量:

  1. public interface Visitor {
  2. /** 对应于NodeA的访问操作 */
  3. void visit(NodeA nodeA);
  4. /** 对应于NodeB的访问操作 */
  5. void visit(NodeB nodeB);
  6. }

下面是具体访问者角色:

  1. public class VisitorA implements Visitor {
  2. /** 对应于NodeA的访问操作 */
  3. @Override
  4. public void visit(NodeA nodeA) {
  5. System.out.println(nodeA.operationA());
  6. }
  7. /** 对应于NodeB的访问操作 */
  8. @Override
  9. public void visit(NodeB nodeB) {
  10. System.out.println(nodeB.operationB());
  11. }
  12. }
  1. public class VisitorB implements Visitor {
  2. /** 对应于NodeA的访问操作 */
  3. @Override
  4. public void visit(NodeA nodeA) {
  5. System.out.println(nodeA.operationA());
  6. }
  7. /** 对应于NodeB的访问操作 */
  8. @Override
  9. public void visit(NodeB nodeB) {
  10. System.out.println(nodeB.operationB());
  11. }
  12. }

抽象节点声明了一个接收操作:

  1. public abstract class Node {
  2. /** 接收操作 */
  3. public abstract void accept(Visitor visitor);
  4. }

具体节点:

  1. public class NodeA extends Node {
  2. /** 接收操作 */
  3. @Override
  4. public void accept(Visitor visitor) {
  5. visitor.visit(this);
  6. }
  7. /** NodeA特有的商业方法 */
  8. public String operationA() {
  9. return "NodeA被访问了";
  10. }
  11. }

  1. /** 接收操作 */
  2. @Override
  3. public void accept(Visitor visitor) {
  4. visitor.visit(this);
  5. }
  6. /** NodeB特有的商业方法 */
  7. public String operationB() {
  8. return "NodeB被访问了";
  9. }
  10. }

结构对象角色,含有一个聚集,并且向外界提供了一个add方法作为对聚集的管理操作,通过调用这个方法,可以动态的增加一个新的节点:

  1. public class ObjectStructure {
  2. private List<Node> nodes;
  3. private Node node;
  4. public ObjectStructure() {
  5. nodes = new ArrayList<>();
  6. }
  7. /** 执行访问操作 */
  8. public void action(Visitor visitor) {
  9. for (Node n : nodes) {
  10. n.accept(visitor);
  11. }
  12. }
  13. public void add(Node node) {
  14. nodes.add(node);
  15. }
  16. }

客户端:

  1. public class Client {
  2. private static ObjectStructure structure;
  3. private static Visitor visitor;
  4. public static void main(String[] args) {
  5. //创建一个结构对象
  6. structure = new ObjectStructure();
  7. //给结构增加一个节点
  8. structure.add(new NodeA());
  9. //给结构增加一个节点
  10. structure.add(new NodeB());
  11. //创建一个新的访问者
  12. visitor = new VisitorA();
  13. //让访问者访问结构
  14. structure.action(visitor);
  15. }
  16. }

电脑专卖系统

这个电脑专卖店既可以卖组装好的电脑,也可以卖电脑零件,比如CPU、主板、机箱等,也可以卖半成品,比如集成主板等,每一种零件都有自己的价格

下面先定义了一个抽象访问者角色,声明了所有的访问方法:

  1. public interface Visitor {
  2. /** 主板访问操作 */
  3. void visitMainBoard(MainBoard mainBoard);
  4. /** 硬盘访问操作 */
  5. void visitHardDisk(HardDisk disk);
  6. /** cpu访问操作 */
  7. void visitCpu(Cpu cpu);
  8. /** 机箱访问操作 */
  9. void visitCase(Case ce);
  10. /** 集成主板访问操作 */
  11. void visitIntegratedBoard(IntegratedBoard board);
  12. /** 组装电脑访问操作 */
  13. void visitPc(Pc pc);
  14. }

具体访问者角色,用来计算各个零件加在一起的价格:

  1. public class PriceVisitor implements Visitor {
  2. private double total;
  3. public PriceVisitor() {
  4. total = 0.0;
  5. }
  6. /** 商业方法 */
  7. public double value() {
  8. return total;
  9. }
  10. @Override
  11. public void visitMainBoard(MainBoard mainBoard) {
  12. total += mainBoard.price();
  13. }
  14. @Override
  15. public void visitHardDisk(HardDisk disk) {
  16. total += disk.price();
  17. }
  18. @Override
  19. public void visitCpu(Cpu cpu) {
  20. total += cpu.price();
  21. }
  22. @Override
  23. public void visitCase(Case ce) {
  24. total += ce.price();
  25. }
  26. @Override
  27. public void visitIntegratedBoard(IntegratedBoard board) {
  28. total += board.price();
  29. }
  30. @Override
  31. public void visitPc(Pc pc) {
  32. total += pc.price();
  33. }
  34. }

下面是具体访问者角色,用来管理各个零件:

  1. public class InventoryVisitor implements Visitor {
  2. private Vector vector;
  3. public InventoryVisitor() {
  4. vector = new Vector();
  5. }
  6. /** 商业方法 */
  7. public int size() {
  8. return vector.size();
  9. }
  10. @Override
  11. public void visitMainBoard(MainBoard mainBoard) {
  12. vector.add(mainBoard);
  13. }
  14. @Override
  15. public void visitHardDisk(HardDisk disk) {
  16. vector.add(disk);
  17. }
  18. @Override
  19. public void visitCpu(Cpu cpu) {
  20. vector.add(cpu);
  21. }
  22. @Override
  23. public void visitCase(Case ce) {
  24. vector.add(ce);
  25. }
  26. @Override
  27. public void visitIntegratedBoard(IntegratedBoard board) {
  28. vector.add(board);
  29. }
  30. @Override
  31. public void visitPc(Pc pc) {
  32. vector.add(pc);
  33. }
  34. }

抽象节点角色,声明一个接收方法:

  1. public abstract class Equipment {
  2. /** 接收方法 */
  3. public abstract void accept(Visitor visitor);
  4. /** 价格 */
  5. public abstract double price();
  6. }

具体节点角色:

  1. public class MainBoard extends Equipment {
  2. @Override
  3. public void accept(Visitor visitor) {
  4. System.out.println("主板被访问了");
  5. visitor.visitMainBoard(this);
  6. }
  7. @Override
  8. public double price() {
  9. return 100.0;
  10. }
  11. }
  1. public class HardDisk extends Equipment {
  2. @Override
  3. public void accept(Visitor visitor) {
  4. System.out.println("硬盘被访问了");
  5. visitor.visitHardDisk(this);
  6. }
  7. @Override
  8. public double price() {
  9. return 200.0;
  10. }
  11. }
  1. public class Cpu extends Equipment {
  2. @Override
  3. public void accept(Visitor visitor) {
  4. System.out.println("CPU被访问了");
  5. visitor.visitCpu(this);
  6. }
  7. @Override
  8. public double price() {
  9. return 800.0;
  10. }
  11. }
  1. public class Case extends Equipment {
  2. @Override
  3. public void accept(Visitor visitor) {
  4. System.out.println("机箱被访问了");
  5. visitor.visitCase(this);
  6. }
  7. @Override
  8. public double price() {
  9. return 30.0;
  10. }
  11. }

下面是复合节点:

  1. public class Composite extends Equipment {
  2. private Vector vector = new Vector();
  3. @Override
  4. public void accept(Visitor visitor) {
  5. for (int i = 0; i < vector.size(); i++) {
  6. ((Equipment)vector.get(i)).accept(visitor);
  7. }
  8. }
  9. @Override
  10. public double price() {
  11. double total = 0;
  12. for (int i=0; i<vector.size(); i++) {
  13. total += ((Equipment)vector.get(i)).price();
  14. }
  15. return total;
  16. }
  17. public void add(Equipment equipment) {
  18. vector.add(equipment);
  19. }
  20. }
  1. public class IntegratedBoard extends Composite {
  2. public IntegratedBoard() {
  3. super.add(new MainBoard());
  4. super.add(new Cpu());
  5. }
  6. @Override
  7. public void accept(Visitor visitor) {
  8. System.out.println("集成主板被访问了");
  9. super.accept(visitor);
  10. }
  11. }
  1. public class Pc extends Composite {
  2. public Pc() {
  3. super.add(new IntegratedBoard());
  4. super.add(new HardDisk());
  5. super.add(new Case());
  6. }
  7. @Override
  8. public void accept(Visitor visitor) {
  9. System.out.println("组装电脑被访问了");
  10. super.accept(visitor);
  11. }
  12. }

客户端:

  1. public class Client {
  2. private static PriceVisitor priceVisitor;
  3. private static InventoryVisitor inventoryVisitor;
  4. private static Equipment equipment;
  5. public static void main(String[] args) {
  6. equipment = new Pc();
  7. priceVisitor = new PriceVisitor();
  8. equipment.accept(priceVisitor);
  9. System.out.println("价格:" + priceVisitor.value());
  10. inventoryVisitor = new InventoryVisitor();
  11. equipment.accept(inventoryVisitor);
  12. System.out.println("零件数:" + inventoryVisitor.size());
  13. }
  14. }

由电脑专卖系统引发的Java设计模式:访问者模式的更多相关文章

  1. java设计模式---访问者模式

      Java深入到一定程度,就不可避免的碰到设计模式这一概念,了解设计模式,将使自 己对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统中应用广 泛,遵循一定的编程模式,才能使自 ...

  2. Java设计模式—访问者模式

    原文地址:http://www.cnblogs.com/java-my-life/archive/2012/06/14/2545381.html 总结的太棒啦,导致自己看了都不想总结了...... 在 ...

  3. JAVA 设计模式 访问者模式

    用途 访问者模式 (Visitor) 表示一个作用于某对象结构中的各元素的操作. 它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 访问者模式是一种行为型模式. 用途

  4. Java设计模式-访问者模式(Visitor)

    访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化.访问者模式适用于数据结构相对稳定算法又易变化的系统.因为访问者模式使得算法操作增加变得容易.若系统数据结构对象易于变化,经 ...

  5. Java设计模式——组合模式

    JAVA 设计模式 组合模式 用途 组合模式 (Component) 将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模 ...

  6. 3.java设计模式-建造者模式

    Java设计模式-建造者模式 在<JAVA与模式>一书中开头是这样描述建造(Builder)模式的: 建造模式是对象的创建模式.建造模式可以将一个产品的内部表象(internal repr ...

  7. Java设计模式——外观模式

    JAVA 设计模式 外观模式 用途 外观模式 (Facade) 为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 外观模式是一种结构型模式. 结构

  8. 【设计模式】Java设计模式 - 外观模式

    Java设计模式 - 外观模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起记录分享自己 ...

  9. java设计模式--单列模式

    java设计模式--单列模式 单列模式定义:确保一个类只有一个实例,并提供一个全局访问点. 下面是几种实现单列模式的Demo,每个Demo都有自己的优缺点: Demo1: /** * 单列模式需要满足 ...

随机推荐

  1. C/C++子函数参数传递,堆栈帧、堆栈参数详解

    本文转载自C/C++子函数参数传递,堆栈帧.堆栈参数详解 导语 因为参数传递和汇编语言有很大联系,之后会出现较多x86汇编代码. 该文会先讲一下x86的堆栈参数传递过程,然后再分析C/C++子函数是怎 ...

  2. 微信小程序(七)-项目实例(原生框架 MINA转云开发)==02-云开发-配置

    云开发:1.就是用云函数的型式来使用云存储和云数据库完成各种操作!     2.只关注调什么函数,完成什么功能即可,无需关心HTTP请求哪一套!     3.此模式不代表没有服务器,只是部署在云环境中 ...

  3. 微信小程序:解决小程序中有些格式如webpiPhone手机暂不支持的问题

    问题:小程序中有些格式是iPhone手机暂不支持的,如goods_introduce中的webp格式,在小程序的模拟器中是可以正常显示webp格式的,但是一旦你做真机调试,很可能某些iPhone手机是 ...

  4. molloc堆区的动态内存分配

    [前言]前面有一篇文章介绍了堆区栈区的区别.栈区的核心主要集中在操作一个栈结构,一般由操作系统维护.堆区,主要是我们程序员来维护,核心就是动态内存分配. 这篇笔记结束就不在高新CSAPP的读书笔记了, ...

  5. 看完我的笔记不懂也会懂----javascript模块化

    JavaScript模块化 模块化引子 模块化的历史进化 模块化规范 CommonJS规范 Node.js(服务器端) 下项目的结构分析 browerify(浏览器端) 下项目的结构分析 AMD规范 ...

  6. 后端程序员之路 53、A Tour of Go-3

    #method    - Methods        - Go does not have classes. However, you can define methods on types.    ...

  7. 关于PHP的isset()函数

      1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title></title> 5 <meta cha ...

  8. 关于djangorestframework

    djangorestframework技术文档 restfrmework规范 开发模式 普通开发为前端和后端代码放在一起写 前后端分离为前后端交互统统为ajax进行交互 前后端分离 优点:分工明细,节 ...

  9. FreeBSD 入门 哲学与玄学

    『哲学与玄学』 FreeBSD 是一种 UNIX 哲学(如模块化,一切皆文件等,见< UNIX 编程艺术>❩的发展,也是学院派的代表作品.她是一套工具集,她存在目的是为了让人们更好的生活. ...

  10. Apache配置 6. 访问日记切割

    日志一直记录总有一天会把整个磁盘占满,所以有必要让它自动切割,并删除老的日志文件 (1)配置 (1)配置 # vim /usr/local/apache2 .4/conf/extra/httpd-vh ...