访问者模式
封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
访问者模式优缺点
-
扩展性良好: 元素类可以通过接受不同的访问者来实现对不同操作的扩展。
-
符合单一职责原则: 元素类中需要封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作,使用访问者模式一方面符合单一职责原则,另一方面,因为被封装的操作通常来说都是易变的,所以当发生变化时,就可以在不改变元素类本身的前提下,实现对变化部分的扩展。
应用场景
-
一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
-
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor模式使得你可以将相关的操作集中起来 定义在一个类中。
-
当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
-
定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
访问者模式结构
-
Visitor 抽象访问者角色: 为该对象结构中具体元素角色声明一个访问操作接口。该操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色,这样访问者就可以通过该元素角色的特定接口直接访问它。
-
ConcreteVisitor.具体访问者角色: 实现Visitor声明的接口。
-
Element 定义一个接受访问操作: 它以一个访问者(Visitor)作为参数。
-
ConcreteElement 具体元素: 实现了抽象元素(Element)所定义的接受操作接口。
-
ObjectStructure 结构对象角色: 这是使用访问者模式必备的角色。它具备以下特性:能枚举它的元素;可以提供一个高层接口以允许访问者访问它的元素;如有需要,可以设计成一个复合对象或者一个聚集(如一个列表或无序集合)。
实现流程
Visitor: 抽象访问者角色
public interface IVisitor {
void visit(ConcreteElement1 el1);
void visit(ConcreteElement2 el2);
}
ConcreteVisitor:具体访问者角色
public class Visitor implements IVisitor{
@Override
public void visit(ConcreteElement1 el1) {
el1.doSomething();
}
@Override
public void visit(ConcreteElement2 el2) {
el2.doSomething();
}
}
Element:定义一个接受访问操作(accept())
public abstract class Element {
public abstract void accept(IVisitor visitor);
public abstract void doSomething();
}
ObjectStructure:结构对象角色
public class ConcreteElement1 extends Element{
@Override
public void accept(IVisitor visitor) {
visitor.visit(this);
}
@Override
public void doSomething() {
System.out.println("这是元素1");
}
}
ObjectStructure:结构对象角色
public class ConcreteElement2 extends Element{
@Override
public void accept(IVisitor visitor) {
visitor.visit(this);
}
@Override
public void doSomething() {
System.out.println("这是元素2");
}
}
客户端
public class Client {
public static void main(String[] args) {
List<Element> list = ObjectStruture.getList();
for (Element e:list){
e.accept(new Visitor());
}
}
}