设计模式学习总结(二十二)--访问者模式

定义

访问者模式就是表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式适用于数据结构相对稳定的系统。

角色

  • Vistor: 抽象访问者。为该对象结构中的ConcreteElement的每一个类声明的一个操作。
  • ConcreteVisitor: 具体访问者。实现Visitor申明的每一个操作,每一个操作实现算法的一部分。
  • Element: 抽象元素。定义一个Accept操作,它以一个访问者为参数。
  • ConcreteElement: 具体元素 。实现Accept操作。
  • ObjectStructure: 对象结构。能够枚举它的元素,可以提供一个高层的接口来允许访问者访问它的元素。

优缺点

优点

  • 使得新增新的访问操作变得更加简单。
  • 能够使得用户在不修改现有类的层次结构下,定义该类层次结构的操作。
  • 将有关元素对象的访问行为集中到一个访问者对象中,而不是分散搞一个个的元素类中。

缺点

  • 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,违背了“开闭原则”的要求。
  • 破坏封装。当采用访问者模式的时候,就会打破组合类的封装。
  • 比较难理解。貌似是最难的设计模式了。

实例

以药房拿药为例

抽象药:

/**
 * 抽象药
 */
public abstract class Medicine {
    protected String name;
    protected double price;

    public Medicine (String name,double price){
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public abstract void accept(Visitor visitor);
}

具体药:

public class MedicineA extends Medicine{

    public MedicineA(String name, double price) {
        super(name, price);
    }

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

public class MedicineB extends Medicine{

    public MedicineB(String name, double price) {
        super(name, price);
    }

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

抽象访问者:

/**
 *  抽象访问者
 */
public abstract class Visitor {
    protected String name;

    public void setName(String name) {
        this.name = name;
    }

    public abstract void visitor(MedicineA a);
    public abstract void visitor(MedicineB a);

}

具体访问者:

/**
 * 药房工作者
 */
public class WorkerOfPharmacy extends Visitor{

    public void visitor(MedicineA a) {
        System.out.println("药房工作者:" + name + "拿药 :" + a.getName());
    }

    public void visitor(MedicineB b) {
        System.out.println("药房工作者:" + name + "拿药 :" + b.getName());
    }

}

/**
 * 划价员
 */
public class Charger  extends Visitor{

    @Override
    public void visitor(MedicineA a) {
        System.out.println("划价员:" + name +"给药" + a.getName() +"划价:" + a.getPrice());
    }
    @Override
    public void visitor(MedicineB b) {
        System.out.println("划价员:" + name +"给药" + b.getName() +"划价:" + b.getPrice());
    }
}

处方:

public class Presciption {
    List<Medicine> list = new ArrayList<Medicine>();

    public void accept(Visitor visitor){
        Iterator<Medicine> iterator = list.iterator();

        while (iterator.hasNext()) {
            iterator.next().accept(visitor);
        }
    }

    public void addMedicine(Medicine medicine){
        list.add(medicine);
    }

    public void removeMedicien(Medicine medicine){
        list.remove(medicine);
    }
}

测试:

public static void main(String[] args) {
    Medicine a = new MedicineA("板蓝根", 11.0);
    Medicine b = new MedicineB("感康", 14.3);

    Presciption presciption = new Presciption();
    presciption.addMedicine(a);
    presciption.addMedicine(b);

    Visitor charger = new Charger();
    charger.setName("张三");

    Visitor workerOfPharmacy = new WorkerOfPharmacy();
    workerOfPharmacy.setName("李四");

    presciption.accept(charger);
    System.out.println("-------------------------------------");
    presciption.accept(workerOfPharmacy);
}

控制台输出:

划价员:张三给药板蓝根划价:11.0
划价员:张三给药感康划价:14.3
-------------------------------------
药房工作者:李四拿药 :板蓝根
药房工作者:李四拿药 :感康

原文地址:https://www.cnblogs.com/markLogZhu/p/11582731.html

时间: 2024-09-30 23:58:47

设计模式学习总结(二十二)--访问者模式的相关文章

设计模式学习笔记(十二:生成器模式)

1.1概述 将一个复杂对象的构建与它的表示分离,使同样的构建过程可以创建不同的表示.这就是生产器模式的定义. 如果一个类中有若干个成员变量是其他类声明的对象,那么该类创建的对象就可以包含若干个其他对象作为其成员.习惯上把一个对象中的成员对象称作它的组件,例如,几何(Geometry)类含有三角形(Triangle)类.矩形(Rectangle)类和圆(Circle)类声明的对象,那么几何类就可以创建一个由三角形.矩形和圆形组成的几何图形,三角形.长方形和圆形就是当前几何图形中的组件. 但是,在编

我的MYSQL学习心得(十二)

原文:我的MYSQL学习心得(十二) 我的MYSQL学习心得(十二) 我的MYSQL学习心得(一) 我的MYSQL学习心得(二) 我的MYSQL学习心得(三) 我的MYSQL学习心得(四) 我的MYSQL学习心得(五) 我的MYSQL学习心得(六) 我的MYSQL学习心得(七) 我的MYSQL学习心得(八) 我的MYSQL学习心得(九) 我的MYSQL学习心得(十) 我的MYSQL学习心得(十一) 这一篇<我的MYSQL学习心得(二)>将会讲解MYSQL的触发器 触发器是一个特殊的存储过程,不

【Unity 3D】学习笔记四十二:粒子特效

粒子特效 粒子特效的原理是将若干粒子无规则的组合在一起,来模拟火焰,爆炸,水滴,雾气等效果.要使用粒子特效首先要创建,在hierarchy视图中点击create--particle system即可 粒子发射器 粒子发射器是用于设定粒子的发射属性,比如说粒子的大小,数量和速度等.在创建完粒子对象后,在右侧inspector视图中便可以看到所有的粒子属性: emit:是否是使用粒子发射器. min size:粒子最小尺寸. max size:粒子最大尺寸. min energy:粒子的最小生命周期

【Unity 3D】学习笔记三十二:游戏元素——游戏光源

游戏光源 在3D游戏中,光源是一个非常具有特色的游戏组件.用来提升游戏画面质感的.如果没有加入光源,游戏场景可能就会显得很昏暗.在unity中提供了三种不同的光源类型:点光源,聚光灯,平行光. 点光源 顾名思义,点光源是从一个点向周围散发出光的光源,就像电灯一样.创建点光源在hierarchy视图中点击create--point light: 创建完以后,点击点光源对象,在右侧inspector视图中可以看到点光源的所有信息: type:光源的类型.有point(点光源),directional

SaltStack 学习笔记 - 第十二篇: SaltStack Web 界面

SaltStack 有自身的用python开发的web界面halite,好处是基于python,可以跟salt的api无缝配合,确定就比较明显,需要个性化对web界面进行定制的会比较麻烦,如果喜欢体验该界面的可以参考下面的文章  http://rfyiamcool.blog.51cto.com/1030776/1275443/ 我是运用另一个python+php来进行web开发,具体需要的工具有在我的另一篇文章里面介绍过,这里再重新进行整个开发介绍 首先介绍php 跟python通信的工具 pp

马哥学习笔记三十二——计算机及操作系统原理

缓存方式: 直接映射 N路关联 缓存策略: write through:通写 write back:回写 进程类别: 交互式进程(IO密集型) 批处理进程(CPU密集型) 实时进程(Real-time) CPU: 时间片长,优先级低IO:时间片短,优先级高 Linux优先级:priority 实时优先级: 1-99,数字越小,优先级越低 静态优先级:100-139,数据越小,优先级越高 实时优先级比静态优先级高 nice值:调整静态优先级   -20,19:100,139   0:120 ps

Android学习路线(二十二)运用Fragment构建动态UI——构建一个灵活的UI

先占个位置,下次翻译 :p When designing your application to support a wide range of screen sizes, you can reuse your fragments in different layout configurations to optimize the user experience based on the available screen space. For example, on a handset devi

Android学习路线(十二)Activity生命周期——启动一个Activity

先占个位置,过会儿来翻译,:p Unlike other programming paradigms in which apps are launched with a main()method, the Android system initiates code in an Activity instance by invoking specific callback methods that correspond to specific stages of its lifecycle. Th

quick-cocos2d-x 学习系列之十二 关于websocket

quick-cocos2d-x 学习系列之十二 关于websocket 1.  概念 百度百科:WebSocket protocol 是HTML5一种新的协议.它实现了浏览器与服务器全双工通信(full-duplex). 在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 flex ajax bridge,可以在javascript中使用这两项功能. 可

全栈JavaScript之路( 二十二 )IE 专有扩展——文档模式

ie8 引入了一个新的概念,"文档模式" ,页面的文档模式决定了,可以使用什么功能.也就是说,"文档模式",决定你了你可以使用哪个级别的css,在javascript可以使用哪些API, 以及如何对待文档类型(doctype). 两种方式修改: 通过 meta 标签修改,<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7"> 在服务器端修改, res.