首页 > 代码库 > 访问者模式
访问者模式
在阎宏博士的《JAVA与模式》一书中开头是这样描述访问者(Visitor)模式的:
访问者模式是对象的行为模式。访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。
从定义可以看出结构对象是使用访问者模式的必备条件,而且这个结构对象必须存在遍历自身各个对象的方法
访问者模式结构:
访问者角色(Visitor): 为该对象结构中具体元素角色声明一个访问操作接口.
具体访问者角色(Concrete Visitor): 实现每个由访问者角色(Visitor)声明的操作.
元素角色(Element): 定义一个Accept操作,它以一个访问者为参数.
具体元素角色(Concrete Element): 实现由元素角色提供的Accept操作.
对象结构角色(Object Structure): 这是使用访问者模式必备的角色. 它要具备以下特征: 能枚举它的元素; 可以提供一个高层的接口以允许该访问者访问它的元素; 可以是一个复合(组合模式)或是一个集合, 如一个列表或一个无序集合.
实例1:
public interface Visitor { public void visit(GladiolusConcreteElement gladiolus); public void visit(ChrysanthemumConreteElement chrysanthemum); } public interface FlowerElement { public void accept(Visitor visitor); } public class GladiolusConcreteElement implements FlowerElement { @Override public void accept(final Visitor visitor) { visitor.visit(this); } } public class ChrysanthemumConreteElement implements FlowerElement { @Override public void accept(final Visitor visitor) { visitor.visit(this); } } public class GladiolusVisitor implements Visitor { @Override public void visit(final GladiolusConcreteElement gladiolus) { System.out.println(this.getClass().getSimpleName() + " access " + gladiolus.getClass().getSimpleName()); } @Override public void visit(final ChrysanthemumConreteElement chrysanthemum) { System.out.println(this.getClass().getSimpleName() + " access " + chrysanthemum.getClass().getSimpleName()); } } public class ChrysanthemumConreteElement implements FlowerElement { @Override public void accept(final Visitor visitor) { visitor.visit(this); } } public class ObjectStructure { private final List<FlowerElement> elements = new ArrayList<FlowerElement>(); public void addElement(final FlowerElement e) { elements.add(e); } public void removeElement(final FlowerElement e) { elements.remove(e); } public void accept(final Visitor visitor) { for (final FlowerElement e : elements) { e.accept(visitor); } } } public class Client { public static void main(final String[] args) { final ObjectStructure os = new ObjectStructure(); os.addElement(new GladiolusConcreteElement()); os.addElement(new ChrysanthemumConreteElement()); final GladiolusVisitor gVisitor = new GladiolusVisitor(); final ChrysanthemumVisitor chVisitor = new ChrysanthemumVisitor(); os.accept(gVisitor); os.accept(chVisitor); } }
运行结果:
GladiolusVisitor access GladiolusConcreteElement GladiolusVisitor access ChrysanthemumConreteElement ChrysanthemumVisitor access GladiolusConcreteElement ChrysanthemumVisitor access ChrysanthemumConreteElement
实例2:
interface Service { public void accept(Visitor visitor); } class Visitor { public void process(Service service) { // 基本业务 System.out.println("基本业务"); } public void process(Saving service) { // 存款 System.out.println("存款"); } public void process(Draw service) { // 提款 System.out.println("提款"); } public void process(Fund service) {
// 基金 System.out.println("基金"); } } class Saving implements Service { public void accept(Visitor visitor) { visitor.process(this); } } class Draw implements Service { public void accept(Visitor visitor) { visitor.process(this); } } class Fund implements Service { public void accept(Visitor visitor) { visitor.process(this); } }
从上面例子可以看出,访问者借助的是java的动态分配机制,使得visitor可以顺利的执行相应对象的方法
//正常逻辑实现 Service service1 = new Saving(); Service service2 = new Fund(); Service service3 = new Draw(); List<Service> ls = new ArrayList<Service>(); ls.add(service1); ls.add(service2); ls.add(service3); for (Service service : ls) { if (service instanceof Saving) { System.out.println("存款"); } else if (service instanceof Fund) { System.out.println("基金"); } else if (service instanceof Draw) { System.out.println("提款"); } } //上述的问题是随着业务量增大,代码维护量会非常的大,需要不断的去判断 //采用访问者模式解决 Service saving = new Saving(); Service fund = new Fund(); Service draw = new Draw(); Visitor visitor = new Visitor(); saving.accept(visitor); fund.accept(visitor); draw.accept(visitor);
//上述中accept中实际上有观察者的影子 实际上 访问者我们也可以理解成一个对业务熟悉的观察者
//他不断观察是否有新的业务需求 有的话 进行相应的业务处理
小结:
采用Visitor的好处如上面说到的那样,当需要改变其中一项业务的处理时,不需要每个地方都进行修改,而只需要改动Visitor类中相应的处理函数就可以了。也就是说它适合于业务处理时常发生变动的情况。
当然,Visitor也有它自身的限制。它不适合于业务数量的经常变化,因为一旦新增或删除一些Service时,需要对visitor进行相应的增删。也就是说具体Service与Visitor是耦合的
其实也是将责任抽象成一个个具体的类,从而避免在一个类中既处理逻辑又带有功能,违反了面向对象原则--责任单一
有以下情形可以考虑使用访问者模式:
1、一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。
3、当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
4、 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
访问者模式