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)));}}
当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>>
- How does the Visitor Pattern come from?如何推导出访问者模式
- 访问者模式(Visitor Pattern)
- 访问者模式(Visitor Pattern)
- 访问者模式(Visitor Pattern)
- 访问者模式(Visitor Pattern)
- 访问者模式 Visitor Pattern
- 访问者模式(Visitor Pattern)
- 访问者模式【VISITOR PATTERN 】
- 访问者模式【Visitor Pattern】
- 访问者模式(Visitor Pattern)
- 访问者模式(Visitor Pattern)
- 访问者模式 (visitor pattern)
- 访问者模式 Visitor Pattern
- 访问者模式【Visitor Pattern】
- 访问者模式 | Visitor Pattern
- Visitor Pattern(访问者模式)
- Design Pattern Visitor 访问者模式
- 访问者模式(Visitor Pattern)
- Android 中 EventBus 的使用(2):缓存事件
- iOS企业开发者账号申请流程(未完待续)
- 主成分分析(Principal components analysis)-最大方差解释
- 学习笔记
- NDK在自己的SO中调用第三方SO
- How does the Visitor Pattern come from?如何推导出访问者模式
- JPA:一对多、多对一关系
- 关于调用skin++会出现无法解析的外部符号问题解决方案
- Android通知Notification
- spark sql
- 对线性回归,logistic回归和一般回归的认识
- 看JavaScript设计模式这本书之后的收获(1)
- ViewController生命周期
- 日志收集工具