借用大神李建忠的思路,应用一个模式的时候,我们的动机是什么,如果最初的动机都不清楚,那只能是为了用模式而用模式了。
用一种模式,是为了解决一类实际项目中遇到的问题。
进入正题:
访问者模式的使用动机是什么?
答曰:我们在开发时,为了程序能更好的扩展、解耦。。。总之一系列的目的吧,我们会使用接口来实现多态。也就是说,一个方法,不同的子类中有不同的实现。
然后。。。很久以后,我们要在接口中加一个方法,怎么做呢?1->修改接口;2->修改每一个实现类(实现这个方法嘛)。如果是个成熟的程序,这种修改,是可能带来风险的。
在这里讲一个小事,在初学时,项目经理设计了一套实现,有四种订单,暂且称为ABCD,也就是有四个实现类,继承同一个接口,最初他们都有相同的数据库操作,增删改查。这样的抽象-实现方式没有任何问题。直到有一天,我临时参与到这个活里,
新加了一种订单:E。E里面除了有增删改查的操作外,还有其他的操作业务,比如对订单的统计。怎么办?
当初我首先想,不在接口里定义,只在实现类E里面写这个方法。这样对其他的程序没有修改。可是随之而来的问题就是:这样还是面向接口编程了?为什么要面向接口?一是封闭实现,只对外公布接口;二还是为了扩展方便。试想,我都深入到实现类中了,我也就破坏了人家最初的设计结构了,对不?
那怎么办?没办法,只能接口中定义,然后在ABCDE中,分别实现,当然,ABCD中没做任何处理,仅仅是为了适应这次修改,代价,可想而知。牵一发动五肢了。
我们能避免这种修改吗?学了这个模式之前,我知道能,但是咱不会啊。现在看来,原本可以轻松搞定的。
我们的软件设计理念i什么?对了,对修改封闭,对扩展开放,是为封闭开放原则。
也就是说,我不想动原来的所有,或者大部分代码,我通过写新的内容,然后做一下关联,来应对这种变化。
怎么办?
访问者模式登场。
首先,定义一个访问者接口:IVisitor,里面定义一系列对外开放的方法,Visit(T),这些方法是重载的,每一个分别对应于ABCD这四个类。所以参数T就分别是ABCD的对象。
然后,每增加一种操作(比如统计操作),就继承一个新类,里面对四个Visit()方法分别实现。
而在原来的业务逻辑接口及ABCD类中,做如下工作:
接口中定义抽象方法:Accept(IVisitor iv);
实现类TongJiVisitor中这样实现:Accept(IVisitor iv){iv.visit(this);}
作用就是允许这个访问者过来访问。
Client端:
如果我要做统计工作:
xx.accept(new TongJiVisitor());
比如又加了一种需求:打印订单信息:
xx.accept(new PrintVisitor());
以上是本人学习《设计模式之禅》的心得,欢迎交流。