第三篇 遍历对象 第十二章 - 访问者模式
迭代器模式主要用于遍历类型相同、集中管理的对象,那些类型各异的散落对象又该如何遍历呢?
我们引用《桃花源记》中的故事,看看访问者模式提供的设计思路。
假设桃花源中有林、山、人三种类型的对象,误入秘境的武陵人需要挨个“访问”它们。
// 林
public class Grove {}
// 山
public class Mountain {}
// 人
public class Person {}
// 抽象访问者
public interface Visitor {
// 访林
public void visit(Grove obj);
// 访山
public void visit(Mountain obj);
// 访人
public void visit(Person obj);
}
直接遍历类型各异的散落对象并不容易。
方便起见,我们先统一受访者的表观类型——使它们实现同一个接口。我们在这个接口里定义好接纳访问者的方法,使访问者有机会了解受访者的内部细节。
完整的代码如下。
// 抽象受访者
public interface Visitable {
// 接纳访问者
public void accept(Visitor visitor);
}
// 林
public class Grove implements Visitable {
public void show() {
// 芳草鲜美,落英缤纷。
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 山
public class Mountain implements Visitable {
public void describe() {
// 山有小口,仿佛若有光。
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 人
public class Person implements Visitable {
public void live() {
// 黄发垂髫,并怡然自乐。
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
表观类型统一后,可以将受访对象放到容器里集中管理。
如下所示。
// 桃花源
public class PeachStream {
// 对象容器
java.util.List<Visitable> list = new java.util.ArrayList<>();
// 添加对象
public boolean add(Visitable obj) {
return this.list.add(obj);
}
// 使用迭代器模式遍历容器中的对象
public void accept(Visitor visitor) {
for (Visitable obj : list) {
obj.accept(visitor);
}
}
}
至此,武陵人可以轻松访问桃花源中的林、山、人了。
// 具体访问者
public class WulingVisitor implements Visitor {
// 访林
@Override
public void visit(Grove obj) {
obj.show();
}
// 访山
@Override
public void visit(Mountain obj) {
obj.describe();
}
// 访人
@Override
public void visit(Person obj) {
obj.live();
}
}
// 测试类
public class Test {
public void test() {
PeachStream obj = new PeachStream();// 桃花源
obj.add(new Grove());// 林
obj.add(new Mountain());// 山
obj.add(new Person());// 人
obj.accept(new WulingVisitor());// 武陵人开始访问
}
}
浙公网安备 33010602011771号