访客模式 无痕模式 区别
我猜想很多人都知道来访者设计模式,这在《四人帮的设计模式:可重用的面向对象软件的元素》一书中有描述。 模式本身不是很复杂(随着许多设计模式的发展):
![访客UML类图](https://i-blog.csdnimg.cn/blog_migrate/6c6bc24da91fa97b4e1c4a95dc1ddb2b.png)
我很久以来就认识来访者,但是我从来不需要它... Java本机处理多态:方法调用基于调用对象的运行时类型,而不是其编译类型。
interfaceAnimal{
voideat();
}
publicclassDogimplementsAnimal{
publicvoideat(){
System.out.println("Gnaws bones");
}
}
Animala=newDog();
a.eats();// Prints "Gnaws bones"
但是,这对于参数类型来说并不是很好( 即完全):
publicclassFeeder{
publicvoidfeed(Dogd){
d.eat();
}
publicvoidfeed(Catc){
c.eat();
}
}
Feederfeeder=newFeeder();
Objecto=newDog();
feeder.feed(o);// Cannot compile!
此问题称为双重调度,因为它需要调用基于实例和参数类型的方法,而Java本身无法处理该方法。 为了使其编译,需要以下代码:
if(oinstanceofDog){
feeder.feed((Dog)o);
}elseif(oinstanceofCat){
feeder.feed((Cat)o);
}else{
thrownewRuntimeException("Invalid type");
}
使用更多可用的重载方法,这将变得更加复杂-并使用更多参数,则将成倍增加。 在维护阶段,添加更多重载方法需要读取if
整体并进行更新。 多个参数是通过嵌入if
来实现的,这在可维护性方面更加糟糕。 访客模式是一种完美的实现方式,无需if
,而以Animal
类上的单个方法为代价。
publicinterfaceAnimal{
voideat();
voidaccept(Visitorv);
}
publicclassCat{
publicvoideat(){...}
publicvoidaccept(Visitorv){
v.visit(this);
}
}
publicclassDog{
publicvoideat(){...}
publicvoidaccept(Visitorv){
v.visit(this);
}
}
publicclassFeederVisitor{
publicvoidvisit(Catc){
newFeeder().feed(c);
}
publicvoidvisit(Dogd){
newFeeder().feed(d);
}
}
优点:
- 任何地方都没有评估逻辑
- 仅
Animal
和FeederVisitor
之间的依从性仅限于visit()
方法 - 因此,当添加新的
Animal
子类型时,Feeder
类型保持不变 - 添加新的
Animal
子类型时,FeederVisitor
类型可能会实现其他方法来处理它 - 其他横切逻辑可能遵循相同的模式, 例如 ,训练动物新技巧的火车功能
举个简单的例子,花这么多篇幅似乎显得有些矫kill过正。 但是,我的经验告诉我,上述简单的东西注定会随着时间的流逝而变得越来越复杂。
访客模式 无痕模式 区别