概念:

  Visitor模式也叫访问者模式,是行为模式之一,它分离对象的数据和行为,使用Visitor模式,可以不修改已有类的情况下,增加新的操作。

  访问者模式的应用示例

  比如有一个公园,有一到多个不同的组成部分;该公园存在多个访问者:清洁工A负责打扫公园的A部分,清洁工B负责打扫公园的B部分,公园的管理者负责检点各项事务是否完成,上级领导可以视察公园等等。也就是说,对于同一个公园,不同的访问者有不同的行为操作,而且访问者的种类也可能需要根据时间的推移而变化(行为的扩展性)。根据软件设计的开闭原则(对修改关闭,对扩展开放),我们怎么样实现这种需求呢?

  访问者模式的结构

  访问者模式的角色和职责

  1、 访问者角色(Visitor):为该对象结构中具体元素角色声明一个访问操作接口。该操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色。这样访问者就可以通过该元素角色的特定接口直接访问它。

  2、具体访问者角色(Concrete Visitor):实现每个由访问者角色(Visitor)声明的操作。

  3、元素角色(Element):定义一个Accept操作,它以一个访问者为参数。

  4、具体元素角色(Concrete Element):实现由元素角色提供的Accept操作。

  5、对象结构角色(Object Structure):这是使用访问者模式必备的角色。它要具备以下特征:能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个复合(组合模式)或是一个集合,如一个列表或一个无序集合。

  下面,用代码来实现一下访问者模式

  首先,先新建一个公园的各个组成部分(因为有了各个组成部分才能有公园,所以我们先建各个组成部分,再建公园)

  新建一个公园各个部分的抽象类元素角色Element),需要传入一个访问者,一会后面会创建访问者

 /*
* 公园每一部分的抽象
*/
public interface ParkElement {
//用来接纳访问者
public void accept(Visitor visitor);
}

  再新建公园的各个部分,这是具体元素角色(Concrete Element)

  关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。

 public class ParkA implements ParkElement{

     @Override
public void accept(Visitor visitor) {
visitor.visit(this);
} }
 public class ParkB implements ParkElement{

     @Override
public void accept(Visitor visitor) {
visitor.visit(this);
} }

  有了公园的各个部分,我们就可以开始新建公园了,这就是对象结构角色(Object Structure)

 /*
* 整个公园,其中包含了公园的各个部分
*/
public class Park implements ParkElement{
private ParkA parkA;
private ParkB parkB; public Park() {
super();
this.parkA = new ParkA();
this.parkB = new ParkB();
} @Override
public void accept(Visitor visitor) {
visitor.visit(this);
parkA.accept(visitor);
parkB.accept(visitor);
} }

  有了公园,我们就可以开始建造访问者了,先建造访问者角色(Visitor)

 /*
* 其中包含访问公园不同区域的重载方法,其中重载的参数Park,ParkA,PArkB,不仅可以获得公园的信息,还用来作为重载的条件
*/
public interface Visitor {
public void visit(Park park);
public void visit(ParkA parkA);
public void visit(ParkB parkB);
}

  然后在建造具体访问者角色,就是具体访问者角色(Concrete Visitor)

 /*
* 清洁工A负责公园A的清洁情况
*/
public class VisitorA implements Visitor{ @Override
public void visit(Park park) {
} @Override
public void visit(ParkA parkA) {
System.out.println("清洁工A完成了公园A的卫生");
} @Override
public void visit(ParkB parkB) {
} }
 /*
* 清洁工B负责公园B的清洁情况
*/
public class VisitorB implements Visitor{ @Override
public void visit(Park park) {
} @Override
public void visit(ParkA parkA) {
} @Override
public void visit(ParkB parkB) {
System.out.println("清洁工B完成了公园B的卫生");
} }
 /*
* 公园管理员负责检查整个公园的卫生情况
*/
public class VisitorManager implements Visitor{ @Override
public void visit(Park park) {
System.out.println("管理员:负责公园的卫生检查");
} @Override
public void visit(ParkA parkA) {
System.out.println("管理员:负责公园A部分的卫生检查");
} @Override
public void visit(ParkB parkB) {
System.out.println("管理员:负责公园B部分的卫生检查");
} }

  最后,新建一个客户端

 public class MainClass {
public static void main(String[] args) {
Park park = new Park(); Visitor visitorA = new VisitorA();
park.accept(visitorA); Visitor visitorB = new VisitorB();
park.accept(visitorB); VisitorManager visitorManager = new VisitorManager();
park.accept(visitorManager);
}
}

  结果:

  这样,一个访问者模式的例子就完成了,一定把上面的程序看懂

   访问者模式的使用意图:

  主要将数据结构与数据操作分离,解决了稳定的数据结构和易变的操作耦合问题。   

   访问者模式的使用场景:

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

  1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。

  2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。

   访问者模式的优缺点:

  优点:

  1、符合单一职责原则。

  2、优秀的扩展性。

  3、灵活性。

  缺点:

  1、具体元素对访问者公布细节,违反了迪米特原则。

  2、具体元素变更比较困难。

  3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。

  注意事项:  

  访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。

java设计模式-----24、访问者模式的更多相关文章

  1. 折腾Java设计模式之访问者模式

    博客原文地址:折腾Java设计模式之访问者模式 访问者模式 Represent an operation to be performed on the elements of an object st ...

  2. JAVA设计模式之访问者模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述访问者(Visitor)模式的: 访问者模式是对象的行为模式.访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要 ...

  3. 15.java设计模式之访问者模式

    基本需求: 电脑需要键盘鼠标等固定的组件组成 现在分为个人,组织等去买电脑,而同一种组件对不同的人(访问者)做出不同的折扣,从而电脑的价格也不一样 传统的解决方法:在组件内部进行判断访问人的类型,从而 ...

  4. 由电脑专卖系统引发的Java设计模式:访问者模式

    目录 定义 意图 解决问题 何时使用 优缺点 结构 电脑专卖系统 定义 访问者模式是对象的行为型模式,它的目的是封装一些施加于某些数据结构元素之上的操作,一旦这些操作需要修改的话,接收这个操作的数据结 ...

  5. C#设计模式总结 C#设计模式(22)——访问者模式(Vistor Pattern) C#设计模式总结 .NET Core launch.json 简介 利用Bootstrap Paginator插件和knockout.js完成分页功能 图片在线裁剪和图片上传总结 循序渐进学.Net Core Web Api开发系列【2】:利用Swagger调试WebApi

    C#设计模式总结 一. 设计原则 使用设计模式的根本原因是适应变化,提高代码复用率,使软件更具有可维护性和可扩展性.并且,在进行设计的时候,也需要遵循以下几个原则:单一职责原则.开放封闭原则.里氏代替 ...

  6. Java设计模式——装饰者模式

    JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...

  7. 浅析JAVA设计模式之工厂模式(一)

    1 工厂模式简单介绍 工厂模式的定义:简单地说,用来实例化对象,取代new操作. 工厂模式专门负责将大量有共同接口的类实例化.工作模式能够动态决定将哪一个类实例化.不用先知道每次要实例化哪一个类. 工 ...

  8. 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern)

    原文:乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) 作者:webabc ...

  9. JAVA设计模式--装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...

  10. 折腾Java设计模式之建造者模式

    博文原址:折腾Java设计模式之建造者模式 建造者模式 Separate the construction of a complex object from its representation, a ...

随机推荐

  1. Yii2框架 数据库常用操作

    通用: use yii\db\Query; $query = new Query(); 查询: Query: $rows = (new \yii\db\Query()) ->select(['c ...

  2. java urlrewrite实现伪静态化

    1.示例 http://www.onlyfun.com/goods/company.jsp?companyId=455326 ==> http://www.onlyfun.com/company ...

  3. underscore.js源码研究(6)

    概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...

  4. POJ 2845

    #include <iostream> #include <string> #include <algorithm> #define MAXN 350 using ...

  5. python中文画图显示乱码解决办法

    最近使用notebook Python中的matplotlib作图,发现中文设置的坐标标签和title都显示为乱码,用了网上的许多教程都不管用,嘴后解决的方式是设置下述的两行即可搞定: plt.rcP ...

  6. android开发学习——day5

    活动跳转部分代码显式intent @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(saved ...

  7. iOS事件分发

    前段时间项目有一个需求,要在点击闪屏的时候做一些处理,刚接到这个需求觉得很简单啊,在原有的view上加个button或者手势识别啥的,后面实现的时候发现还是有点坑.无论我在闪屏上面加button还是手 ...

  8. notecase的下载与安装(全网最详细)(图文详解)

    不多说,直接上干货! notecase是什么? 一个按照树状结构来组织文档内容的笔记管理程序 1.双击 2.aceept 3.选择安装所放置的目录路径 4.选择开启目录文件夹 我这里,保持默认 建议默 ...

  9. dispatchEvent相关内容

    意思就是:手动触发事件. 我的理解是:类似于jquery中的trigger方法,可以在点击某个dom的时候,触发另一个dom的事件,下面一个我自己尝试的例子: <!DOCTYPE html> ...

  10. Linux系列:Ubuntu/fedora实用小技巧—禁止自动锁屏、设置免密码自动登录、免密码执行sudo操作

    首先声明:该文虽以Ubuntu 13.04为例,同样适用于Fedora 17(已测试),但在较低版本的Ubuntu下可能有所差异,具体看后面的注意事项. 技巧目录: 解决Ubuntu下每隔几分钟自动锁 ...