设计模式学习笔记(二十一:访问者模式)
1.1概述
表示将一个作用于某对象结构中的各个元素的操作。它可以在不改变各个元素的类的前提下定义作用于这些元素的新操作。这就是访问者模式的定义。
编写类的时候,可能在该类中编写了若干个实例方法,该类的对象通过调用这些实例方法操作其成员变量表明所产生的行为。在某些设计中,可能需要定义作用于类的成员变量的新操作,而且这个新操作不应当由该类中的某个实例方法来承担。
例如,有一个电表(Ammeter)类,在电表类中,electricAmount成员变量的值表示用电量,showElectricAmount()方法返回electricAmount变量的值来收取电费。现在的问题是:希望根据用电量来计算电费,即根据electricAmount变量的值来收取电费。显然,不应该在Ammeter类中增加计算电费的方法(单表本身不能计算出电费)。在实际生活中,应当由物业部门的“计表员”观察电表的用电量,然后按着有关收费标准计算出电费。访问者模式建议让一个称作访问者的对象访问Ammeter对象(电表),以便定义作用于Ammeter对象上的操作。在访问者模式中,“计表员”是AmmeterVisitor类的实例,称作Ammeter类实例的访问者,AmmeterVisitor类中有一个计算电费的方法:
void visit(Ammeter ammeter);
该方法的参数是Ammeter类的实例,因此只要将Ammeter类的实例传递给该方法的参数,AmmeterVisitor类的实例就可以计算出电费(PS:假设1度点0.88元):
double visit(Ammeter ammer){
charge = ammeter.showElectricAmount()*0.88;
return charge;
}
按着访问者模式,应当在Ammeter类中增加一个接受访问者的方法。Ammeter类中接受访问者的方法可如下定义:
void accept(AmmeterVisitor v){
v.visit(this); //将自身传递给参数指定的访问者
}
因此,一个Ammeter类的实例通过调用accept()方法,并向该方法传递一个访问者,即AmmeterVisitor的实例,然后Ammeter类的实例再将自身传递给访问者就可以知道自己需要交纳多少电费了。Ammeter和AmmeterVisitor类的类图如下图一所示:
图一:有关缴纳电费关系类图(PS:类图画的有点不规范,仅作参考哦)
Ammeter类有了接受访问者的accept(AmmeterVisitor visitor)方法后,可以不改变Ammeter类就能定义作用于Ammeter对象的成员变量上的新操作,比如,可以让accept(AmmeterVisitor visitor)的参数是AmmeterVisitor类的一个实例,该实例布局根据Ammeter对象的成员变量计算出正常的电费,而且还可以计算超电量应缴纳的额外电费。
1.2模式的结构
访问者模式包括以下五种角色:
(1)抽象元素(Element):一个抽象类,该类定义了接受访问者的accept操作。
(2)具体元素(Concrete Element):Element的子类。
(3)对象结构(Object Structure):一个集合,用于存放Element对象,提供遍历它自己的方法。
(4)抽象访问者(Visitor):一个接口,该接口定义操作对象(Concrete Element的实例)的方法。
(5)具体访问者(Concrete Visitor):实现Visitor接口的类。
访问者模式结构的类图如下图二所示:
图二:访问者模式的类图(PS:类图画的有点不规范,仅作参考哦)
1.3访问者模式的优点
(1)可以在不改变一个集合中元素类的情况下,增加新的施加于该元素上的新操作。
(2)可以将集合中各个元素的某些操作集中到访问者中,不仅便于集合的维护,也有利于集合中元素的复用。
1.4适合使用访问者模式的情景
(1)一个对象结构中,比如某个集合中,包含有很多对象,想对集合中对象增加新的操作。
(2)需要对集合中的对象进行很多不同并且不相关的操作,而又不想修改对象的类,就可以使用访问者模式。访问者模式可以在Visitor类中集中定义一些关于集合中对象的操作。
1.5访问者模式的使用
以下通过一个简单的问题来描述怎样使用访问者模式。这个简单的问题是:公司考核若干个大学生和研究生,以决定是否录用。在这个问题中,大学生和研究生都有自己的成绩,但是他们不能依据自己的成就制定录用标准,录用标准必须公司来确定。
首先看一下本实例构建框架具体类和1.2模式的结构中类图的对应关系,如下图所示:
(1)抽象元素(Element)
本问题中,抽象元素角色是Student类,代码如下:
package com.liuzhen.twenty_one_visitor;public abstract class Sudent {public abstract void accept(Visitor v); }
(2)具体元素(Concrete Element)
本问题中,有两个具体元素,分别是Undergraduate和GraduateStudent类,这两个类分别表示“大学生”和“研究生”,二者的成绩体系是不同的,代码如下:
Undergraduate类代码:
package com.liuzhen.twenty_one_visitor;public class Undergraduate extends Sudent {double math,english;String name;Undergraduate(String name,double math,double english){this.name = name;this.math = math;this.english = english;}public double getMath(){return math;}public double getEnglish(){return english;}public String getName(){return name;}public void accept(Visitor v){v.visit(this);} }
GraduateStudent类代码:
package com.liuzhen.twenty_one_visitor;public class GraduateStudent extends Sudent {double math,english,physics;String name;GraduateStudent(String name,double math,double english,double physics){this.name = name;this.math = math;this.english = english;this.physics = physics;}public double getMath(){return math;}public double getEnglish(){return english;}public String getName(){return name;}public double getPhysics(){return physics;}public void accept(Visitor v){v.visit(this);} }
(3)对象结构(Object Structure)
本问题中,该角色是java.util包中的ArrayList集合。
(4)抽象访问者(Visitor)
本问题中,抽象访问者接口是Visitor,代码如下:
package com.liuzhen.twenty_one_visitor;public interface Visitor {public void visit(Undergraduate stu);public void visit(GraduateStudent stu); }
(5)具体访问者(Visitor)
本问题中,具体访问者是公司Company,代码如下:
package com.liuzhen.twenty_one_visitor;public class Company implements Visitor {public void visit(Undergraduate stu) {double math = stu.getMath();double english = stu.getEnglish();if(math > 80 && english > 90)System.out.println(stu.getName()+"被录用");}public void visit(GraduateStudent stu) {double math = stu.getMath();double english = stu.getEnglish();double physics = stu.getPhysics();if(math > 80 && english > 90 && physics > 70)System.out.println(stu.getName()+"被录用");}}
(6)具体使用
通过Twenty_oneApplication类来具体实现上述相关类和接口,来实现访问者模式的运用,其代码如下:
package com.liuzhen.twenty_one_visitor;import java.util.ArrayList; import java.util.Iterator;public class Twenty_oneApplication {public static void main(String[] args) {Visitor visitor = new Company();ArrayList<Sudent> studentList = new ArrayList<Sudent>();Sudent student = null;studentList.add(student = new Undergraduate("张三",67,68));studentList.add(student = new Undergraduate("李四",80,88));studentList.add(student = new Undergraduate("王五",85,95));studentList.add(student = new GraduateStudent("小明",67,68,70));studentList.add(student = new GraduateStudent("小红",80,90,70));studentList.add(student = new GraduateStudent("小白",95,95,90));Iterator<Sudent> iter = studentList.iterator();while(iter.hasNext()){Sudent stu = iter.next();stu.accept(visitor);}}}
运行结果:
王五被录用 小白被录用
参考资料:
1.Java设计模式/耿祥义,张跃平著.——北京:清华大学出版社,2009.5
设计模式学习笔记(二十一:访问者模式)相关推荐
- 设计模式学习笔记——享元(Flyweight)模式
设计模式学习笔记--享元(Flyweight)模式 @(设计模式)[设计模式, 享元模式, flyweight] 设计模式学习笔记享元Flyweight模式 基本介绍 享元案例 类图 实现代码 Big ...
- 设计模式学习笔记——中介者(Mediator)模式
设计模式学习笔记--中介者(Mediator)模式 @(设计模式)[设计模式, 中介者模式, Mediator] 设计模式学习笔记中介者Mediator模式 基本介绍 中介者案例 类图 实现代码 Me ...
- 设计模式学习笔记——单例(Singleton)模式
设计模式学习笔记--单例(Singleton)模式 @(设计模式)[设计模式, 单例模式, Singleton, 懒汉式, 饿汉式] 设计模式学习笔记单例Singleton模式 基本介绍 单例案例 类 ...
- python3.4学习笔记(二十一) python实现指定字符串补全空格、前面填充0的方法
python3.4学习笔记(二十一) python实现指定字符串补全空格.前面填充0的方法 Python zfill()方法返回指定长度的字符串,原字符串右对齐,前面填充0. zfill()方法语法: ...
- C#设计模式之二十一访问者模式(Visitor Pattern)【行为型】
一.引言 今天我们开始讲"行为型"设计模式的第九个模式,该模式是[访问者模式],英文名称是:Visitor Pattern.如果按老规矩,先从名称上来看看这个模式,我根本不能获得任 ...
- 设计模式学习笔记--Mediator 中介者模式
我们知道面向对象应用程序是由一组为了提供某种服务而彼此交互的对象组成.当彼此引用的对象数量比较少时,此时对象之间就为直接交互(点对点).而当对象的数量增加时,这种直接交互会导致对象之间复杂的.混乱的引 ...
- Mr.J-- jQuery学习笔记(二十一)--模拟微博页面
先看之前的节点操作方法:Mr.J-- jQuery学习笔记(二十)--节点操作方法 Mr.J-- jQuery学习笔记(五)--属性及属性节点 Mr.J-- jQuery学习笔记(十一)--事件委托 ...
- 设计模式学习笔记--Flyweight享元模式
Flyweight模式也叫享元模式,是由GoF提出的23种设计模式中的一种.Flyweight模式是构造型模式之一,它通过与其他类似对象共享数据来减小内存占用,所以叫享元. 此模式解决的是由于大量 ...
- 设计模式学习笔记--享元(Flyweight)模式
写在模式学习之前 什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方案,这就是软件模式:每一个模式描述了一个在我们程序设计中经常发生的问题,以及该问题的解决方案:当我们碰到模式 ...
- C#设计模式学习笔记:(4)建造者模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7614630.html,记录一下学习过程以备后续查用.一.引言在现实生活中,我们经常会遇到一些构成比较复杂的物 ...
最新文章
- Nature | 有机合成的数字化
- 数据库入门浅析:ASP.NET与MySQL连接
- ext4 文件系统新特性
- javaweb设置servlet
- android线程控制UI更新(Handler 、post()、postDelayed()、postAtTime)
- 合成小丹(dp+二进制按位或+结论)
- 【论文分享】ACL 2020 信息抽取与问答系统
- 【排版】LaTeX公式编辑器-Texlive入门
- python安装numpy库出错_numpy安装失败-小失误
- 实现原理 扫描枪_激光条码扫描枪原理及五大组成部分!
- 大话卷积神经网络(CNN)
- 深蓝学院 浙江大学免费开源课程 !
- 计算机安全中心无法启动,如何解决Win10无法启动Windows安全中心服务问题
- 明天省赛,我都还不太熟悉Dev - C++,怎么切换成C++11了?它的报错看不懂呀,那花八分钟看看这篇文章吧~解决你的困惑。
- wamp php imagick,wamp2.5安装imagick
- Unity3D游戏开发-宣雨松读书摘要(2015-4-17 18:36)
- bash管道符开启子进程
- Linux 重启网络服务
- 切比雪夫不等式例题讲解_「高中数学」柯西不等式,最全解析,高考必备,搞定最后十分...
- 电脑格式化后文件还能恢复吗?好用方法分享