How does the Visitor Pattern come from?如何推导出访问者模式

来源:互联网 发布:域名仲裁机构 编辑:程序博客网 时间:2024/06/14 10:27

下面用making pizza例子来推导visitor pattern。假设我们要制作一种含有各种口味的pizza。

step1.我们先抽象出各种pizza和调料。

public abstract class Pizza {}//面包皮class Crust extends Pizza {}//乳酪class Cheese extends Pizza {Pizza p;public Cheese(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}}//橄榄油class Olive extends Pizza {Pizza p;public Olive(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}}//凤尾鱼class Anchovy extends Pizza {Pizza p;public Anchovy(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}}//ok.now we are able to make kinds of Pizza//new Cheese(new Anchovy(new Olive(new Crust()))))
定义好这些类后我们就可以制作各种pizza了。

new Cheese(new Anchovy(new Olive(new Crust()))));

new Anchovy(new Anchovy(new Anchovy(new Crust()))))


step2.现在我们要求能对制作出来的pizza有三种功能:可以在每一种anchovy上添加cheese,可以去掉anchovy,可以将所有的anchovy替换成cheese.

ok,我们可以用abstract来实现。

abstract class Pizza {abstract Pizza remAnchovy();abstract Pizza substAnchovyWithCheese();abstract Pizza topAnchovyWithCheese();}//consume nothing and produce crust onlyclass Crust extends Pizza {@OverridePizza remAnchovy() {// TODO Auto-generated method stubreturn new Crust();}@OverridePizza substAnchovyWithCheese() {// TODO Auto-generated method stubreturn new Crust();}@OverridePizza topAnchovyWithCheese() {// TODO Auto-generated method stubreturn new Crust();}}class Cheese extends Pizza {Pizza p;public Cheese(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}@OverridePizza remAnchovy() {// TODO Auto-generated method stubreturn new Cheese(p.remAnchovy());}@OverridePizza substAnchovyWithCheese() {// TODO Auto-generated method stubreturn new Cheese(p.substAnchovyWithCheese());}@OverridePizza topAnchovyWithCheese() {// TODO Auto-generated method stubreturn new Cheese(p.topAnchovyWithCheese());}}class Olive extends Pizza {Pizza p;public Olive(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}@OverridePizza remAnchovy() {// TODO Auto-generated method stubreturn new Olive(p.remAnchovy());}@OverridePizza substAnchovyWithCheese() {// TODO Auto-generated method stubreturn new Olive(p.substAnchovyWithCheese());}@OverridePizza topAnchovyWithCheese() {// TODO Auto-generated method stubreturn new Olive(p.topAnchovyWithCheese());}}class Anchovy extends Pizza {Pizza p;public Anchovy(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}@Override<span style="white-space:pre"></span>Pizza remAnchovy() {// TODO Auto-generated method stubreturn p.remAnchovy();}<span style="white-space:pre"></span>@OverridePizza substAnchovyWithCheese() {// TODO Auto-generated method stubreturn new Cheese(p.substAnchovyWithCheese());}@OverridePizza topAnchovyWithCheese() {// TODO Auto-generated method stubreturn new Cheese(new Anchovy(p.topAnchovyWithCheese()));}}

通过让对象new一个自己来复制自己的方式,我们很快就复制了一个符合要求的pizza。每个对象中的成员p起链表作用,将所有的调料连接起来,绑定到crust上。

ok,现在我们可以使用我们的方法了。

new Cheese(new Anchovy(new Olive(new Crust())))).remAnchovy();

new Anchovy(new Anchovy(new Anchovy(new Crust())))).substAnchovyWithCheese();

new Anchovy(new Anchovy(new Anchovy(new Crust())))).topAnchovyWithCheese();


step3.假如我们想添加一个新的方法,比如在去掉Olive,我们就要在每一个类实现一遍,好麻烦。我们可以考虑把每个类的具体实现都方法都放到一个类中,实现数据跟接口的分离。

public class RemAnchovy {Pizza forCrust() { return new Crust();}Pizza forCheese(Pizza _p) {return new Cheese(_p.remAnchovy());}Pizza forOlive(Pizza _p) {return new Olive(_p.remAnchovy());}Pizza forAnchovy(Pizza _p) {return _p.remAnchovy();}}public class SubstAWC {Pizza forCrust() { return new Crust();}Pizza forCheese(Pizza _p) {return new Cheese(_p.substAnchovyWithCheese());}Pizza forOlive(Pizza _p) {return new Olive(_p.substAnchovyWithCheese());}Pizza forAnchovy(Pizza _p) {return new Cheese(_p.substAnchovyWithCheese());}}public class TopAWC {Pizza forCrust() { return new Crust();}Pizza forCheese(Pizza _p) {return new Cheese(_p.topAnchovyWithCheese());}Pizza forOlive(Pizza _p) {return new Olive(_p.topAnchovyWithCheese());}Pizza forAnchovy(Pizza _p) {return new Cheese(new Anchovy(_p.topAnchovyWithCheese()));}}
abstract class Pizza {<span style="white-space:pre"></span>RemAnchovy raFn = new RemAnchovy();SubstAWC subFn = new SubstAWC();TopAWC topFn = new TopAWC();abstract Pizza remAnchovy();abstract Pizza substAnchovyWithCheese();abstract Pizza topAnchovyWithCheese();}//consume nothing and produce crust onlyclass Crust extends Pizza {@OverridePizza remAnchovy() {// TODO Auto-generated method stubreturn raFn.forCrust();}@OverridePizza substAnchovyWithCheese() {// TODO Auto-generated method stubreturn subFn.forCrust();}@OverridePizza topAnchovyWithCheese() {// TODO Auto-generated method stubreturn topFn.forCrust();}}class Cheese extends Pizza {Pizza p;public Cheese(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}@OverridePizza remAnchovy() {// TODO Auto-generated method stubreturn raFn.forCheese(p);}@OverridePizza substAnchovyWithCheese() {// TODO Auto-generated method stubreturn subFn.forCheese(p);}@OverridePizza topAnchovyWithCheese() {// TODO Auto-generated method stubreturn topFn.forCheese(p);}}class Olive extends Pizza {Pizza p;public Olive(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}@OverridePizza remAnchovy() {// TODO Auto-generated method stubreturn raFn.forOlive(p);}@OverridePizza substAnchovyWithCheese() {// TODO Auto-generated method stubreturn subFn.forOlive(p);}@OverridePizza topAnchovyWithCheese() {// TODO Auto-generated method stubreturn topFn.forOlive(p);}}class Anchovy extends Pizza {Pizza p;public Anchovy(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}@OverridePizza remAnchovy() {// TODO Auto-generated method stubreturn raFn.forAnchovy(p);}@OverridePizza substAnchovyWithCheese() {// TODO Auto-generated method stubreturn subFn.forAnchovy(p);}@OverridePizza topAnchovyWithCheese() {// TODO Auto-generated method stubreturn topFn.forAnchovy(p);}}

我们把rem,sub,top三个方法对每个类的具体实现分别放到RemAnchovy,  SubstAWC, TopAWC类中,这样子当要对所有的子类修改rem方法时,不用跑到每个类中具体去修改,将每个子类的数据跟其方法实现了分离。

同样,我们用之前的方式调用rem,sub,top的出来的效果还是一样。


step4.简化

观察RemAnchovy,  SubstAWC, TopAWC这三个类的定义,他们是不是都有一样的接口,只是实现的细节稍微有些不同而已?Pizza的子类也是差不多。我们可以对他们做进一步的抽象。

interface PizzaVisitor {Pizza forCrust();Pizza forCheese(Pizza _p);Pizza forOlive(Pizza _p);Pizza forAnchovy(Pizza _p);}class RemAnchovy implements PizzaVisitor{public Pizza forCrust() { return new Crust();}public Pizza forCheese(Pizza _p) {return new Cheese(_p.accept(this));}public Pizza forOlive(Pizza _p) {return new Olive(_p.accept(this));}public Pizza forAnchovy(Pizza _p) {return _p.accept(this);}}public class SubstAWC implements PizzaVisitor{public Pizza forCrust() { return new Crust();}public Pizza forCheese(Pizza _p) {return new Cheese(_p.accept(this));}public Pizza forOlive(Pizza _p) {return new Olive(_p.accept(this));}public Pizza forAnchovy(Pizza _p) {return new Cheese(_p.accept(this));}}class TopAWC implements PizzaVisitor{public Pizza forCrust() { return new Crust();}public Pizza forCheese(Pizza _p) {return new Cheese(_p.accept(this));}public Pizza forOlive(Pizza _p) {return new Olive(_p.accept(this));}public Pizza forAnchovy(Pizza _p) {return new Cheese(new Anchovy(_p.accept(this)));}}
abstract class Pizza {abstract Pizza accept(PizzaVisitor ask);}//consume nothing and produce crust onlyclass Crust extends Pizza {@OverridePizza accept(PizzaVisitor ask) {// TODO Auto-generated method stubreturn ask.forCrust();}}class Cheese extends Pizza {Pizza p;public Cheese(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}@OverridePizza accept(PizzaVisitor ask) {// TODO Auto-generated method stubreturn ask.forCheese(p);}}class Olive extends Pizza {Pizza p;public Olive(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}@OverridePizza accept(PizzaVisitor ask) {// TODO Auto-generated method stubreturn ask.forOlive(p);}}class Anchovy extends Pizza {Pizza p;public Anchovy(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}@OverridePizza accept(PizzaVisitor ask) {// TODO Auto-generated method stubreturn ask.forAnchovy(p);}}

简化后,我们调用各种方法的方式也随之发生变化:

new Cheese(new Anchovy(new Olive(new Crust())))).accept( new remAnchovy() );

new Anchovy(new Anchovy(new Anchovy(new Crust())))).accept( substAnchovyWithCheese() );

new Anchovy(new Anchovy(new Anchovy(new Crust())))).accept( topAnchovyWithCheese() );


step5.generalize(再抽象)

我们现在想要任意删减pizza原料的种类,而不仅仅是Anchovy。同样,更换原料时可以任意替换种类。这个时候,由于我们已经将Pizza的子类的操作方法和数据分离,我们只需修改visitor类即可。

interface PizzaVisitor {Pizza forCrust();Pizza forCheese(Pizza _p);Pizza forOlive(Pizza _p);Pizza forAnchovy(Pizza _p);}class Rem implements PizzaVisitor{Pizza pizza;Rem(Pizza p) {pizza = p;}public Pizza forCrust() { return new Crust();}public Pizza forCheese(Pizza _p) {if(pizza.equals(_p)) {return _p.accept(this);} else {return new Cheese(_p.accept(this));}}public Pizza forOlive(Pizza _p) {if(pizza.equals(_p)) {return _p.accept(this);} else {return new Olive(_p.accept(this));}}public Pizza forAnchovy(Pizza _p) {if(pizza.equals(_p)) {return _p.accept(this);} else {return new Anchovy(_p.accept(this));}}}public class Subst implements PizzaVisitor{Pizza o;Pizza n;public Subst(Pizza _o, Pizza _n) {// TODO Auto-generated constructor stubo = _o;n = _n;}public Pizza forCrust() { return new Crust();}public Pizza forCheese(Pizza _p) {if(_p.equals(o)) {_p.accept(this);return n;} else {return new Cheese(_p.accept(this));}}public Pizza forOlive(Pizza _p) {if(_p.equals(o)) {_p.accept(this);return n;} else {return new Olive(_p.accept(this));}}public Pizza forAnchovy(Pizza _p) {if(_p.equals(o)) {_p.accept(this);return n;} else {return new Cheese(_p.accept(this));}}}class Top implements PizzaVisitor{Pizza o;Pizza n;public Top(Pizza _o, Pizza _n) {// TODO Auto-generated constructor stubo = _o;n = _n;}public Pizza forCrust() { return new Crust();}public Pizza forCheese(Pizza _p) {return new Cheese(_p.accept(this));}public Pizza forOlive(Pizza _p) {return new Olive(_p.accept(this));}public Pizza forAnchovy(Pizza _p) {return new Cheese(new Anchovy(_p.accept(this)));}}


step6.把子类的对象的this指针传递给visitor类

当Pizza的子类的数据成员很多时,visitor的基类PizzaVisitor的基类需要获取Pizza子类的数据时会很麻烦,这个时候需要子类把自己自身的引用传递给visitor类。

interface PizzaVisitor {Pizza forCrust(Crust that);Pizza forCheese(Cheese that);Pizza forOlive(Olive that);Pizza forAnchovy(Anchovy that);}class Rem implements PizzaVisitor{Pizza pizza;Rem(Pizza p) {pizza = p;}public Pizza forCrust(Crust that) { return new Crust();}public Pizza forCheese(Cheese that<) {if(pizza.equals(that)) {return that.p.accept(this);} else {return new Cheese(that.p.accept(this));}}public Pizza forOlive(Olive that) {if(pizza.equals(that)) {return that.p.accept(this);} else {return new Olive(that.p.accept(this));}}public Pizza forAnchovy(Anchovy that) {if(pizza.equals(that)) {return that.p.accept(this);} else {return new Anchovy(that.p.accept(this));}}}public class Subst implements PizzaVisitor{Pizza o;Pizza n;public Subst(Pizza _o, Pizza _n) {// TODO Auto-generated constructor stubo = _o;n = _n;}public Pizza forCrust(Crust that) { return new Crust();}public Pizza forCheese(Cheese that) {if(that.equals(o)) {that.p.accept(this);return n;} else {return new Cheese(that.p.accept(this));}}public Pizza forOlive(Olive that) {if(that.equals(o)) {that.p.accept(this);return n;} else {return new Olive(that.p.accept(this));}}public Pizza forAnchovy(Anchovy that) {if(that.equals(o)) {that.p.accept(this);return n;} else {return new Cheese(that.p.accept(this));}}}class Top implements PizzaVisitor{Pizza o;Pizza n;public Top(Pizza _o, Pizza _n) {// TODO Auto-generated constructor stubo = _o;n = _n;}public Pizza forCrust(Crust that) { return new Crust();}public Pizza forCheese(Cheese that) {return new Cheese(that.p.accept(this));}public Pizza forOlive(Olive that) {return new Olive(that.p.accept(this));}public Pizza forAnchovy(Anchovy that) {return new Cheese(new Anchovy(that.p.accept(this)));}}

abstract class Pizza {abstract Pizza accept(PizzaVisitor ask);}//consume nothing and produce crust onlyclass Crust extends Pizza {@OverridePizza accept(PizzaVisitor ask) {// TODO Auto-generated method stubreturn ask.forCrust(this);}}class Cheese extends Pizza {Pizza p;public Cheese(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}@OverridePizza accept(PizzaVisitor ask) {// TODO Auto-generated method stubreturn ask.forCheese(this);}}class Olive extends Pizza {Pizza p;public Olive(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}@OverridePizza accept(PizzaVisitor ask) {// TODO Auto-generated method stubreturn ask.forOlive(this);}}class Anchovy extends Pizza {Pizza p;public Anchovy(Pizza _p) {// TODO Auto-generated constructor stubp = _p;}@OverridePizza accept(PizzaVisitor ask) {// TODO Auto-generated method stubreturn ask.forAnchovy(this);}}

step7.其它一些小小的trick

interface也可以extends:当我们需要定义一个新的visitor类,但是这个新的类又需要添加新的访问方法,我们又不想去改动原有代码,我们可以从原有的interface 中extends原有的接口和已经定义好的visitor类,然后定义自己需要的接口即可。


具体更加具体的推导过程,请参考Daniel P Friedman的<<a little java, a few pattern>>












0 0