由电脑专卖系统引发的Java设计模式:访问者模式
定义
访问者模式是对象的行为型模式,它的目的是封装一些施加于某些数据结构元素之上的操作,一旦这些操作需要修改的话,接收这个操作的数据结构则可以保持不变
意图
将数据结构与数据操作分离
解决问题
稳定的数据结构和易变的操作耦合问题
何时使用
要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中
优缺点
优点:
- 使得增加新的操作很容易
- 将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中
- 可以跨过几个类的等级结构访问属于不同的等级结构的成员类
缺点:
- 增加新的节点类变的很困难
- 破坏封装
结构

涉及的角色:
- 抽象访问者(Visitor)角色:声明了一个或者多个访问操作,形成所有的具体元素角色必须实现的接口
- 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口,也就是抽象访问者所声明的各个访问操作
- 抽象节点(Node)角色:声明一个接收操作,接收一个访问者对象作为一个参量
- 具体节点(Node)角色:实现了抽象节点所规定的接收操作
- 结构对象(ObjectStructure)角色:有下面的一些职责,可以遍历结构中的所有元素,如果需要,提供一个高层次接口让访问者对象可以访问每一个元素,如果需要,可以设计一个复合对象或者聚集,比如list或set
源码如下:
抽象访问者角色为每一个节点都提供了一个访问操作,并且接收相应的节点对象作为参量:
public interface Visitor {
/** 对应于NodeA的访问操作 */
void visit(NodeA nodeA);
/** 对应于NodeB的访问操作 */
void visit(NodeB nodeB);
}
下面是具体访问者角色:
public class VisitorA implements Visitor {
/** 对应于NodeA的访问操作 */
@Override
public void visit(NodeA nodeA) {
System.out.println(nodeA.operationA());
}
/** 对应于NodeB的访问操作 */
@Override
public void visit(NodeB nodeB) {
System.out.println(nodeB.operationB());
}
}
public class VisitorB implements Visitor {
/** 对应于NodeA的访问操作 */
@Override
public void visit(NodeA nodeA) {
System.out.println(nodeA.operationA());
}
/** 对应于NodeB的访问操作 */
@Override
public void visit(NodeB nodeB) {
System.out.println(nodeB.operationB());
}
}
抽象节点声明了一个接收操作:
public abstract class Node {
/** 接收操作 */
public abstract void accept(Visitor visitor);
}
具体节点:
public class NodeA extends Node {
/** 接收操作 */
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
/** NodeA特有的商业方法 */
public String operationA() {
return "NodeA被访问了";
}
}
/** 接收操作 */
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
/** NodeB特有的商业方法 */
public String operationB() {
return "NodeB被访问了";
}
}
结构对象角色,含有一个聚集,并且向外界提供了一个add方法作为对聚集的管理操作,通过调用这个方法,可以动态的增加一个新的节点:
public class ObjectStructure {
private List<Node> nodes;
private Node node;
public ObjectStructure() {
nodes = new ArrayList<>();
}
/** 执行访问操作 */
public void action(Visitor visitor) {
for (Node n : nodes) {
n.accept(visitor);
}
}
public void add(Node node) {
nodes.add(node);
}
}
客户端:
public class Client {
private static ObjectStructure structure;
private static Visitor visitor;
public static void main(String[] args) {
//创建一个结构对象
structure = new ObjectStructure();
//给结构增加一个节点
structure.add(new NodeA());
//给结构增加一个节点
structure.add(new NodeB());
//创建一个新的访问者
visitor = new VisitorA();
//让访问者访问结构
structure.action(visitor);
}
}

电脑专卖系统
这个电脑专卖店既可以卖组装好的电脑,也可以卖电脑零件,比如CPU、主板、机箱等,也可以卖半成品,比如集成主板等,每一种零件都有自己的价格
下面先定义了一个抽象访问者角色,声明了所有的访问方法:
public interface Visitor {
/** 主板访问操作 */
void visitMainBoard(MainBoard mainBoard);
/** 硬盘访问操作 */
void visitHardDisk(HardDisk disk);
/** cpu访问操作 */
void visitCpu(Cpu cpu);
/** 机箱访问操作 */
void visitCase(Case ce);
/** 集成主板访问操作 */
void visitIntegratedBoard(IntegratedBoard board);
/** 组装电脑访问操作 */
void visitPc(Pc pc);
}
具体访问者角色,用来计算各个零件加在一起的价格:
public class PriceVisitor implements Visitor {
private double total;
public PriceVisitor() {
total = 0.0;
}
/** 商业方法 */
public double value() {
return total;
}
@Override
public void visitMainBoard(MainBoard mainBoard) {
total += mainBoard.price();
}
@Override
public void visitHardDisk(HardDisk disk) {
total += disk.price();
}
@Override
public void visitCpu(Cpu cpu) {
total += cpu.price();
}
@Override
public void visitCase(Case ce) {
total += ce.price();
}
@Override
public void visitIntegratedBoard(IntegratedBoard board) {
total += board.price();
}
@Override
public void visitPc(Pc pc) {
total += pc.price();
}
}
下面是具体访问者角色,用来管理各个零件:
public class InventoryVisitor implements Visitor {
private Vector vector;
public InventoryVisitor() {
vector = new Vector();
}
/** 商业方法 */
public int size() {
return vector.size();
}
@Override
public void visitMainBoard(MainBoard mainBoard) {
vector.add(mainBoard);
}
@Override
public void visitHardDisk(HardDisk disk) {
vector.add(disk);
}
@Override
public void visitCpu(Cpu cpu) {
vector.add(cpu);
}
@Override
public void visitCase(Case ce) {
vector.add(ce);
}
@Override
public void visitIntegratedBoard(IntegratedBoard board) {
vector.add(board);
}
@Override
public void visitPc(Pc pc) {
vector.add(pc);
}
}
抽象节点角色,声明一个接收方法:
public abstract class Equipment {
/** 接收方法 */
public abstract void accept(Visitor visitor);
/** 价格 */
public abstract double price();
}
具体节点角色:
public class MainBoard extends Equipment {
@Override
public void accept(Visitor visitor) {
System.out.println("主板被访问了");
visitor.visitMainBoard(this);
}
@Override
public double price() {
return 100.0;
}
}
public class HardDisk extends Equipment {
@Override
public void accept(Visitor visitor) {
System.out.println("硬盘被访问了");
visitor.visitHardDisk(this);
}
@Override
public double price() {
return 200.0;
}
}
public class Cpu extends Equipment {
@Override
public void accept(Visitor visitor) {
System.out.println("CPU被访问了");
visitor.visitCpu(this);
}
@Override
public double price() {
return 800.0;
}
}
public class Case extends Equipment {
@Override
public void accept(Visitor visitor) {
System.out.println("机箱被访问了");
visitor.visitCase(this);
}
@Override
public double price() {
return 30.0;
}
}
下面是复合节点:
public class Composite extends Equipment {
private Vector vector = new Vector();
@Override
public void accept(Visitor visitor) {
for (int i = 0; i < vector.size(); i++) {
((Equipment)vector.get(i)).accept(visitor);
}
}
@Override
public double price() {
double total = 0;
for (int i=0; i<vector.size(); i++) {
total += ((Equipment)vector.get(i)).price();
}
return total;
}
public void add(Equipment equipment) {
vector.add(equipment);
}
}
public class IntegratedBoard extends Composite {
public IntegratedBoard() {
super.add(new MainBoard());
super.add(new Cpu());
}
@Override
public void accept(Visitor visitor) {
System.out.println("集成主板被访问了");
super.accept(visitor);
}
}
public class Pc extends Composite {
public Pc() {
super.add(new IntegratedBoard());
super.add(new HardDisk());
super.add(new Case());
}
@Override
public void accept(Visitor visitor) {
System.out.println("组装电脑被访问了");
super.accept(visitor);
}
}
客户端:
public class Client {
private static PriceVisitor priceVisitor;
private static InventoryVisitor inventoryVisitor;
private static Equipment equipment;
public static void main(String[] args) {
equipment = new Pc();
priceVisitor = new PriceVisitor();
equipment.accept(priceVisitor);
System.out.println("价格:" + priceVisitor.value());
inventoryVisitor = new InventoryVisitor();
equipment.accept(inventoryVisitor);
System.out.println("零件数:" + inventoryVisitor.size());
}
}

由电脑专卖系统引发的Java设计模式:访问者模式的更多相关文章
- java设计模式---访问者模式
Java深入到一定程度,就不可避免的碰到设计模式这一概念,了解设计模式,将使自 己对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统中应用广 泛,遵循一定的编程模式,才能使自 ...
- Java设计模式—访问者模式
原文地址:http://www.cnblogs.com/java-my-life/archive/2012/06/14/2545381.html 总结的太棒啦,导致自己看了都不想总结了...... 在 ...
- JAVA 设计模式 访问者模式
用途 访问者模式 (Visitor) 表示一个作用于某对象结构中的各元素的操作. 它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 访问者模式是一种行为型模式. 用途
- Java设计模式-访问者模式(Visitor)
访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化.访问者模式适用于数据结构相对稳定算法又易变化的系统.因为访问者模式使得算法操作增加变得容易.若系统数据结构对象易于变化,经 ...
- Java设计模式——组合模式
JAVA 设计模式 组合模式 用途 组合模式 (Component) 将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模 ...
- 3.java设计模式-建造者模式
Java设计模式-建造者模式 在<JAVA与模式>一书中开头是这样描述建造(Builder)模式的: 建造模式是对象的创建模式.建造模式可以将一个产品的内部表象(internal repr ...
- Java设计模式——外观模式
JAVA 设计模式 外观模式 用途 外观模式 (Facade) 为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 外观模式是一种结构型模式. 结构
- 【设计模式】Java设计模式 - 外观模式
Java设计模式 - 外观模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起记录分享自己 ...
- java设计模式--单列模式
java设计模式--单列模式 单列模式定义:确保一个类只有一个实例,并提供一个全局访问点. 下面是几种实现单列模式的Demo,每个Demo都有自己的优缺点: Demo1: /** * 单列模式需要满足 ...
随机推荐
- 【commons-pool2源码】_pre JMX
目录 一.定义 二.demo 三.JMX在commons-pool2中的应用 一.定义 JMX(Java Management Extensions) 简单来说JMX技术提供了一套轻量的标准化的资源管 ...
- ajax缺点
ajax请求在SEO中效率低,SEO就是关键字搜索的匹配度. 比如在百度搜索Java,一般来说内容中出现Java的次数越多排名越靠前,当使用ajax时,它的异步刷新导致必须是页面刷新出来才去刷新数据, ...
- EasyExcel学习
导入依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</a ...
- 力扣832. 翻转图像-C语言实现-简单题
题目 传送门 文本 给定一个二进制矩阵 A,我们想先水平翻转图像,然后反转图像并返回结果. 水平翻转图片就是将图片的每一行都进行翻转,即逆序.例如,水平翻转 [1, 1, 0] 的结果是 [0, 1, ...
- Linux下安装mysql-5.7.28详细步骤
一.下载Mysql 下载地址:https://downloads.mysql.com/archives/community/ 二.环境配置 检测系统是否自带Mysql # rmp -qa|grep m ...
- CSS的定位布局(position)
定位 static(默认值) 没有开启定位 relative 相对定位的性质 包含块(containing block)概念 没有开启定位时包含块就是当前元素最近的祖先块元素 开启绝对定位后的元素包含 ...
- Codeforces Global Round 13
比赛地址 A(水题) 题目链接 题目: 给出一个\(01\)序列,有2种操作:1.将某个位置取反:2.询问\(01\)序列中第\(k\)大的数 解析: 显然维护1的数目即可 #include<b ...
- 肝了很久,冰河整理出这份4万字的SpringCloud与SpringCloudAlibaba学习笔记!!
写在前面 不少小伙伴让我整理下有关SpringCloud和SpringCloudAlibaba的知识点,经过3天的收集和整理,冰河整理出这份4万字的SpringCloud与SpringCloudAli ...
- 防数据泄露_MySQL库和数据安全
目录 攻击场景 外部入侵 内部盗取 防御体系建设 参考 在企业安全建设中有一个方向是防数据泄露,其中一块工作就是保障数据库安全,毕竟这里是数据的源头.当然数据库也分不同的种类,不同类型的数据库的防护手 ...
- 基于OpenSSL的PKI的PKI数字证书系统实现
本篇主要介绍了基于OpenSSL的PKI的PKI数字证书系统实现,利用OpenSSL建立一个CA中心的详细解决方案和建立的具体步骤. 1.PKI数字证书系统设计 PKI数字证书系统主要包括证书颁发机构 ...