访问者模式
概述;
在我们实际的软件开发过程中,有时候我们对同一个对象可能会有不同的处理,对相同元素对象也可能存在不同的操作方式,如处方单,划价人员要根据它来划价,药房工作者要根据它来给药。而且可能会随时增加新的操作,如医院增加新的药物。但是这里有两个元素是保持不变的,或者说很少变:划价人员和药房工作中,变的只不过是他们的操作。所以我们想如果能够将他们的操作抽象化就好了。这里访问者模式就是一个值得考虑的解决方案了。
访问者模式的目的是封装一些施加于某种数据结构元素之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。为不同类型的元素提供多种访问操作方式,且可以在不修改原有系统的情况下增加新的操作方式,这就是访问者模式的模式动机。
访问者模式即表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
首先我们要明确一点就是访问者模式适用于数据结构相对稳定的系统。它是将数据的操作与数据结构进行分离了,如果某个系统的数据结构相对稳定,但是操作算法易于变化的话,就比较适用适用访问者模式,因为访问者模式使得算法操作的增加变得比较简单了。
Vistor: 抽象访问者。为该对象结构中的ConcreteElement的每一个类声明的一个操作。
ConcreteVisitor: 具体访问者。实现Visitor申明的每一个操作,每一个操作实现算法的一部分。
Element: 抽象元素。定义一个Accept操作,它以一个访问者为参数。
ConcreteElement: 具体元素 。实现Accept操作。
ObjectStructure: 对象结构。能够枚举它的元素,可以提供一个高层的接口来允许访问者访问它的元素。
abstract class Visitor{ protected String name; public void setName(String name) { this.name = name; } public abstract void visitor(MedicineA medicine); public abstract void visitor(MedicineB medicine); } 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()); } } 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()); } } abstract class Medicine { protected String name; protected int price; public Medicine(String name, int price) { super(); this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public abstract void accept(Visitor visitor); } class MedicineA extends Medicine { public MedicineA(String name, int price) { super(name, price); // TODO Auto-generated constructor stub } @Override public void accept(Visitor visitor) { // TODO Auto-generated method stub visitor.visitor(this); } } class MedicineB extends Medicine { public MedicineB(String name, int price) { super(name, price); // TODO Auto-generated constructor stub } @Override public void accept(Visitor visitor) { // TODO Auto-generated method stub visitor.visitor(this); } } 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); } } class Client { public static void main(String[] args) { Medicine a = new MedicineA("板蓝根", 11); Medicine b = new MedicineB("感康", 14); 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); } }
优点
1、使得新增新的访问操作变得更加简单。
2、能够使得用户在不修改现有类的层次结构下,定义该类层次结构的操作。
3、将有关元素对象的访问行为集中到一个访问者对象中,而不是分散搞一个个的元素类中。
缺点
1、增加新的元素类很困难。在访问者模式中,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,违背了“开闭原则”的要求。
2、破坏封装。当采用访问者模式的时候,就会打破组合类的封装。
3、比较难理解。貌似是最难的设计模式了。
五、模式适用场景
1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。
六、模式总结
1、访问者模式封装了对象结构元素之上的操作,使得新增元素的操作变得非常简单。所以它比较适用于那么对象结构很少变化的类。
2、访问者模式中对象结构存储了不同类型的元素对象,以供不同访问者访问。