Visitor模式,在不修改已有程序结构的前提下,通过添加额外的“访问者”来完成对已有代码功能的提升。
Visitor模式包括以下几个元素:
1) 访问者接口(Visitor):声明一个访问接口,定义visit接口,有几个元素就定义几个接口方法。接口方法的参数标识了具体访问元素角色,也就是说参数是一个具体类。这个地方也是Visitor的不足,
2) 具体访问者(Concrete Visitor):实现Visitor接口
3) 元素接口(Element):定义一个accept方法,它以访问者接口为参数,这里不是具体的访问者,即不知道具体的访问者。
4) 具体元素(Concrete Element):实现元素(Element)接口中accept方法,控制访问的流程。
5) 对象结构(Object Structure):这是使用Visitor模式必须的角色。它要具备以下特征:能枚举它的元素;可以提供一个高层的接口允许访问者访问它的元素;可以是一个集合,如一个列表或一个无序集合。
类图如下:
具体代码:
public interface Visitor
{
public void visitCollection(Collection collection);
public void visitString(String string);
public void visitFloat(Float float);
}
public class ConcreteVisitor1 implements Visitor
{
//在本方法中,我们实现了对Collection的元素的成功访问
public void visitCollection(Collection collection) {
Iterator iterator = collection.iterator()
while (iterator.hasNext()) {
Object o = iterator.next();
if (o instanceof Visitable)
((Visitable)o).accept(this);
}
public void visitString(String string) {
System.out.println("'"+string+"'");
}
public void visitFloat(Float float) {
System.out.println(float.toString()+"f");
}
}
public interface Visitable
{
public void accept(Visitor visitor);
}
public class StringElement implements Visitable
{
private String value;
public ConcreteElement(String string) {
value = string;
}
//定义accept的具体内容 这里是很简单的一句调用
public void accept(Visitor visitor) {
visitor.visitString(this);
}
}
public class FloatElement implements Visitable
{
private Float value;
public ConcreteElement(Float f) {
value = f;
}
//定义accept的具体内容 这里是很简单的一句调用
public void accept(Visitor visitor) {
visitor.visitFloat(this);
}
}
总结:
1、元素接口和元素类都是依赖Visitor接口,而不是具体实现类,很好的实现了解耦。如果有一个新的元素欢迎Visitor参观,只需要实现Visitable接口,并实现accept方法即可,都不牵涉具体的Visitor。
2、Visitor接口则不然,它依赖具体的元素,也就是说如果元素的类型发生变化如增加一个元素类型,那么Visitor接口和具体实现类都必须大改,这个是Visitor模式严重的缺陷。
3、Visitor模式名副其实,好比旅行社、游客和景点的关系。旅行社就是Visitor接口,这次路线都需要参观哪些景点通常是固定的(接口固定,如果要改变行程,通常很麻烦);游客就这些景点,旅行社给你安排两个小时,你想自己怎么玩都行;景点则以不变应万变。这个比如也许有些不恰当,不过有助于理解这个模式。