Java设计模式之行为型:访问者模式

Java设计模式之行为型:访问者模式

背景:

        去医院看病时,医生会给你一个处方单要你去拿药,拿药我们可以分为两步走:

  • (1)去柜台交钱,划价人员会根据处方单上的药进行划价,交钱。
  • (2)去药房拿药,药房工作者同样根据处方单给你相对应的药。

Java设计模式之行为型:访问者模式

        这里我们就划价和拿药两个步骤进行讨论,这里有三个类,处方单(药)、划价人员、药房工作者。同时划价人员和药房工作者都各自有一个动作:划价、拿药。这里进行最初步的设计如下:

划价人员:

public class Charge {
    public void action(){
        public void action(){
            if("A药".equals(medicine)){
                //A的价格
            }
            if("B药".equals(medicine)){
                //B的价格
            }
            if("C药".equals(medicine)){
                //C的价格
            }
            if("D药".equals(medicine)){
                //D的价格
            }
            if("E药".equals(medicine)){
                //E的价格
            }
            ............
        }
    }
}

药房工作者:

public class WorkerOfPharmacy {
    public void action(){
        if("A药".equals(medicine)){
            //给你A药
        }
        if("B药".equals(medicine)){
            //给你B药
        }
        if("C药".equals(medicine)){
            //给你C药
        }
        if("D药".equals(medicine)){
            //给你D药
        }
        if("E药".equals(medicine)){
            //给你E药
        }
        ............
    }
}

        这样的代码写法,在药品种类少的情况没什么问题,但也存在这么多的 if…else,而且我们可以想象医院里的药是那么多,而且随时都会增加的,增加了药就要改变划价人员和药房工作者的代码,这是我们最不希望改变的。那么有没有办法来解决呢?有,访问者模式提供一中比较好的解决方案。

        在实际开发过程中,我们对同个对象可能存在不同的操作方式,如处方单,划价人员要根据它来划价,药房工作者要根据它来给药。而且可能会随时增加新的操作,如医院增加新的药物,但是这里有两个元素是保持不变的,或者说很少变:划价人员和药房工作中,变的只不过是他们的操作。所以我们想如果能够将他们的操作抽象化就好了,这里访问者模式就是一个值得考虑的解决方案了。

一、什么是访问者模式:

        访问者模式适用于数据结构相对稳定的系统,将数据结构与基于数据的操作进行分离,使得添加作用于这些数据结构的新操作变得简单,并且不需要改变各数据结构,为不同类型的数据结构提供多种访问操作方式,这样是访问者模式的设计动机。

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

       但访问者模式的缺点在于让增加新的元素类变得困难,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,违背了“开闭原则”的要求;

        所以访问者模式适用于对象结构中很少改变,但经常需要在此对象结构上定义新的操作的系统,使得算法操作的增加变得简单;或者需要对一个对象结构中进行很多不同并且不相关的操作,并且需要避免让这些操作污染这些对象,也不希望在增加新操作时修改这些类的场景

二、UML结构图:

Java设计模式之行为型:访问者模式

  • Vistor:抽象访问者,声明了对 ConcreteElement 类的一些操作 
  • ConcreteVisitor:具体访问者,实现抽象访问者中声明的每一个操作
  • Element:抽象元素,定义一个 accept 操作,用于接收具体访问者 
  • ConcreteElement:具体元素 ,实现 accept 操作。 
  • ObjectStructure:对象结构,提供一个高层接口来允许访问者枚举它的元素

        从上面的 UML结构图中我们可以看出,访问者模式主要分为两个层次结构,一个是访问者层次结构,提供了抽象访问者和具体访问者,主要用于声明一些操作;一个是元素层次结构,提供了抽象元素和具体元素,主要用于声明 accept 操作;而对象结构作为两者的桥梁,存储了不同类型的对象,以便不同的访问者来访问,相同访问者可以以不同的方式访问不同的元素,所以在访问者模式中增加新的访问者无需修改现有代码,可扩展行强。

        在访问者模式使用了双分派技术,所谓双分派技术就是在选择方法的时候,不仅仅要根据消息接收者的运行时区别,还要根据参数的运行时区别。在访问者模式中,客户端将具体状态当做参数传递给具体访问者,这里完成第一次分派,然后具体访问者作为参数的“具体状态”中的方法,同时也将自己this作为参数传递进去,这里就完成了第二次分派。双分派意味着得到的执行操作决定于请求的种类和接受者的类型。

二、模式的实现:

        以上面在医院付费、取药为实例。在这个实例中划价员和药房工作者作为访问者,药品作为访问元素、处方单作为对象结构,所以整个UML结构图如下:

Java设计模式之行为型:访问者模式

抽象访问者:Visitor.java

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 b);
}

具体访问者:划价员、Charger.java

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

具体访问者:药房工作者、WorkerOfPharmacy.java

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());
    }
}

抽象元素:Medicine.java

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);
}

具体元素:MedicineA.java

public class MedicineA extends Medicine{
 
    public MedicineA(String name, double price) {
        super(name, price);
    }
 
    public void accept(Visitor visitor) {
        visitor.visitor(this);
    }
}

具体元素:MedicineB.java

public class MedicineB extends Medicine{
 
    public MedicineB(String name, double price) {
        super(name, price);
    }
 
    public void accept(Visitor visitor) {
        visitor.visitor(this);
    }
}

药单:Presciption.java

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);
    }
}

客户端:Client.java

public class Client {
    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);
    }
}

运行结果:

Java设计模式之行为型:访问者模式


设计模式系列文章:

Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)

Java设计模式之创建型:建造者模式

Java设计模式之创建型:单例模式

Java设计模式之创建型:原型模式

Java设计模式之结构型:适配器模式

Java设计模式之结构型:装饰器模式

Java设计模式之结构型:代理模式

Java设计模式之结构型:桥接模式

Java设计模式之结构型:外观模式

Java设计模式之结构型:组合模式

Java设计模式之结构型:享元模式

Java设计模式之行为型:策略模式

Java设计模式之行为型:模板方法模式

Java设计模式之行为型:责任链模式

Java设计模式之行为型:观察者模式

Java设计模式之行为型:访问者模式

Java设计模式之行为型:中介者模式

Java设计模式之行为型:命令模式

Java设计模式之行为型:状态模式

Java设计模式之行为型:备忘录模式

Java设计模式之行为型:迭代器模式

Java设计模式之行为型:解释器模式

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/114637.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • java prototype是什么,Java设计模式之原型模式(Prototype模式)介绍

    java prototype是什么,Java设计模式之原型模式(Prototype模式)介绍Prototype模式定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。如何使用原型模式因为Java中的提供clone()方法来实现对象的克隆,所以Prototype模式…

    2022年10月31日
  • 十四、迭代器模式—— 一个一个的遍历 #和设计模式一起旅行#「建议收藏」

    套路要深…故事背景今天要介绍一下迭代器,首先简单说明一下,什么是迭代器,为什么要使用迭代器。 迭代器(Iterate) 的意思就是反复做某件事情。那为什么要反复做某件事情呢,比如我们有个容器里面装了很好东西(这些东西都是同一类型的),要从容器中取每一个东西出来,就要反复去做一个取出的事情。故事主角迭代器模式 : 提供一种方法顺序访问一个聚合对象中的各个元素,而…

  • Software Model – 软件架构模式和设计模式「建议收藏」

    Software Model – 软件架构模式和设计模式「建议收藏」什么是架构?  软件体系结构通常被称为架构,指可以预制和可重构的软件框架结构。架构尚处在发展期,对于其定义,学术界尚未形成一个统一的意见,而不同角度的视点也会造成软件体系结构的不同理解,以下是一些主流的标准观点。 ANSI/IEEE610.12-1990软

  • Java多线程设计模式:wait/notify机制

    Java多线程设计模式:wait/notify机制

  • JAVA设计模式之原型模式

    定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。类型:创建类模式类图:原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件:实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在ja

  • 四、单例模式—不要冒充我,我只有一个! #和设计模式一起旅行#

    单例模式—不要冒充我! 我就是我 是颜色不一样的烟火 天空开阔 要做最坚强的泡沫。——《我就是我》-张国荣有人冒充我给大家说一个秘密了,其实我和设计模式本来并不认识,是相识于网络上,我们聊的很多,聊人生聊梦想,有一天我突然说,设计模式我们一起去旅行吧,她说可以啊!所以才有着一次的旅行。但是总有一些人想要冒充我,因为他们看到了我和设计模式的这场旅行,那么怎么保证“设计…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号