访问者模式的核心是解决a.foo(b)的双分派问题。所以还是给出一个简单的例子。好人打贱人。好人有南拳、北腿类,贱人有鬼子、棒子、B2等。
访问者模式中客户Test会创建各种各样的对象,只调用一个方法 ”好人"的 打(贱人 j) 方法。
/** * * @author yqj2065 * @version 2014.9 */ public abstract class 好人{ //测试目标 好人 .打(贱人),应该能够找到2*3个方法体 public abstract void 打(贱人 j); abstract void 打JP(); abstract void 打Bar(); abstract void 打B2(); } abstract class 贱人{ public abstract void cmd(好人 x);// Command }
按照采用的技术不同,好人中可以使用重载(程序中就需要用instanceof)、可以使用不同方法名(本例采用的方式)——这些方法由贱人们调用,Test不需要知道,所以采用默认访问控制。注意:不同于Gof,visitXx()中没有参数。
关键点:不同于GoF,Visitor为客户提供了一个统一的访问接口 打(贱人 j)
贱人之所以贱,在GoF中它的方法名不是command而是accept。这个方法的目的是将重载的打(贱人 j) 方法区分开来,转换成 x.打JP()等。
import static tool.Print.*; public class 南拳 extends 好人{ @Override public void 打(贱人 j){ j.cmd(this); } @Override void 打JP(){ pln("南拳.打JP()"); } @Override void 打Bar(){ pln("南拳.打Bar()");} @Override void 打B2(){ pln("南拳.打B2()"); } } class JP extends 贱人{ @Override public void cmd(好人 x){//命令 x.打JP(); } }//其他的北腿、棒子、B2 略
测试:
public static void test访问者(){ 好人 m1 = (好人)God.create("3-30-q");//南拳对象 好人 m2 = (好人)God.create("3-30-t");//北腿对象 贱人 a = (贱人)God.create("3-30-jp"); 贱人 b = (贱人)God.create("3-30-bar"); 贱人 c = (贱人)God.create("3-30-b2"); // x .打(y); m1.打(a); m1.打(b); m1.打(c); m2.打(a); m2.打(b); m2.打(c); }
输出:
南拳.打JP()
南拳.打Bar()
南拳.打B2()
北腿.打JP()
北腿.打Bar()
北腿.打B2()
现在,好人中增加刀客类,按照南拳的样子写一个。测试代码创建一个刀客对象m3,m3.打(a);m3.打(b);m3.打(c);
输出:
南拳.打JP()....
北腿.打B2()
刀客.打JP()
刀客.打Bar()
刀客.打B2()
与抽象工厂类似,增加一个好人的子类很方便;增加一个贱人的子类,好人的类层次都需要修改。
如果愿意,也可以用一个ArrayList把贱人对象放进去,把贱人叫作Element,JP是具体的元素...
这就是访问者模式的基本内容。
时间: 2024-12-25 14:52:47