1. 访问者模式介绍
定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
这句话该怎么理解呢?
可以这么理解,有一个操作,它是作用于一些元素上的,而这些元素属于某一个对象结构。
2. 访问者模式的使用场景
- 加入一个对象中存在着一些与本对象不相干的操作,为了避免这些操作污染这个对象,则可以使用访问者模式来把这些操作封装到访问者中去。
- 假如一组对象中,存在着相似的操作,为了避免出现大量重复的代码,也可以将这些重复的操作封装到访问者中去。
3. 访问者模式的UML类图
角色介绍
Visitor: 接口或者抽象类,它定义了对每一个元素访问的行为,它的参数就是可以访问的元素,它的方法个数理论上来讲与元素个数是一样的,因此访问者模式要求元素的类族要稳定,如果经常添加、移除元素类,必然会导致频繁地修改Visitor接口,如果出现这种情况,则说明不适合使用访问者模式。
ConcreteVisitor: 具体访问者,它需要给出对每一个元素访问时所产生的具体行为。
Element:元素接口或者抽象类,它定义了一个接受访问者的方法,其意义是指每一个元素都要可以被访问者访问。
ElementA、ElementB:具体的元素类,它接受提供访问方法的具体实现,而这个具体实现,通常情况下是使用访问者提供的访问该元素类的具体方法。
ObjectStructure:定义当中所提到的对象结构,对象结构是一个抽象表述,它内部可以迭代这些元素提供访问者方法。
4. 访问者模式的简单实例
- (1)、首先定义一个访问者接口:
public interface Visitor {
public void accept(ElementA elementA);
public void accept(ElementB elementB);
}
上面的访问者接口中,提供了两个accept()方法,表示接受两种具体元素类。
- (2)、下面是定义两个具体的访问者:
ConcreteVisitorA:
public class ConcreteVisitorA implements Visitor {
@Override
public void accept(ElementA elementA) {
String name = elementA.getName();
System.out.println("ElementA ,name: " + name);
}
@Override
public void accept(ElementB elementB) {
String name = elementB.getName();
System.out.println("ElementB ,name: " + name);
}
}
ConcreteVisitorB:
public class ConcreteVisitorB implements Visitor {
@Override
public void accept(ElementA elementA) {
int age = elementA.getAge();
System.out.println("ElementA ,name: " + age);
}
@Override
public void accept(ElementB elementB) {
int age = elementB.getAge();
System.out.println("ElementB ,age: " + age);
}
}
在上面两个具体的访问者中,对每个元素给出了具体的访问行为。不同的访问者对同一个具体元素又有着不同的操作;同一个访问者对不同的元素遇着不同的操作。
- (3)、元素接口或抽象类:
public abstract class Element {
protected String name;
protected int age;
public Element(String name, int age) {
this.name = name;
this.age = age;
}
public abstract void accept(Visitor visitor);
}
元素接口类中定义了acept方法,用来接收Visitor对象,然后接收到的visitor调用本身。不同的具体Visitor方法accept方法对不同的具体元素类有着不同的操作。
- (4)、具体访问者:
ConcreteVisitorA:
public class ConcreteVisitorA implements Visitor {
@Override
public void accept(ElementA elementA) {
String name = elementA.getName();
System.out.println("ElementA ,name: " + name);
}
@Override
public void accept(ElementB elementB) {
String name = elementB.getName();
System.out.println("ElementB ,name: " + name);
}
}
ConcreteVisitorB:
public class ConcreteVisitorB implements Visitor {
@Override
public void accept(ElementA elementA) {
int age = elementA.getAge();
System.out.println("ElementA ,name: " + age);
}
@Override
public void accept(ElementB elementB) {
int age = elementB.getAge();
System.out.println("ElementB ,age: " + age);
}
}
- (5)、对象结构:
public class ObjectStructure {
List<Element> elements = new LinkedList<Element>();
public ObjectStructure() {
elements.add(new ElementA("ElementA", 20));
elements.add(new ElementB("ElementB", 40));
}
public void show(Visitor visitor) {
for (Element element :
elements) {
element.accept(visitor);
}
}
}
上面的对象结构中,有一个集合,内部存放了具体的元素,在show方法里面遍历所有的具体元素,调用所有具体元素的accept方法,将具体元素本身传递给具体的visitor,调用visitor对应的accept方法。
5. 总结
访问者设计模式在Android源码和Android开发中遇到的不多,这里就不再做详细描述了。
- 优点:
- 访问者设计模式符合单一原则,凡事需要封装在访问者中的操作必定是与元素本身关系不打算且是异变操作。
- 被封装的操作通常来说的是异变的,所以当发生变化时,就可以在不改变元素类本身的前提下,实现对变化部分的扩展,具有良好的扩展性。
- 缺点:
- 具体元素变更时,导致修改成本过大。