今天我们先来看一个原理看似很简单,但是理解起来有一定难度,使用场景相对较少的行为型模式:访问者模式。
一、模式原理分析
访问者模式的原始定义是:允许在运行时将一个或多个操作应用于一组对象,将操作与对象结构分离。
这个定义会比较抽象,但是我们依然能看出两个关键点:一个是运行时使用一组对象的一个或多个操作,比如,对不同类型的文件(.pdf、.xml、.properties)进行扫描;另一个是分离对象的操作和对象本身的结构,比如,扫描多个文件夹下的多个文件,对于文件来说,扫描是额外的业务操作,如果在每个文件对象上都加一个扫描操作,太过于冗余,而扫描操作具有统一性,非常适合访问者模式。
所以说,访问者模式核心关注点是分离一组对象结构和对象的操作,对象结构可以各不相同,但必须以某一个或一组操作作为连接的中心点。换句话说,访问者模式是以行为(某一个操作)作为扩展对象功能的出发点,在不改变已有类的功能的前提下进行批量扩展。
访问者模式的UML图如下:
从这个 UML 图中,我们能看出访问者模式包含的关键角色有四个。
-
访问者类(Visitor):这是一个接口或抽象类,定义声明所有可访问类的访问操作。
-
访问者实现类(VisitorBehavior):实现在访问者类中声明的所有访问方法。
-
访问角色类(Element):定义一个可以获取访问操作的接口,这是使客户端对象能够“访问”的入口点。
-
访问角色实现类(Element A 等):实现访问角色类接口的具体实现类,将访问者对象传递给此对象作为参数。
也就是说,访问者模式可以在不改变各来访类的前提下定义作用于这些来访类的新操作。比如,在没有二维码的时代,旅游景区检票大门提供的访问者实现类就是人工检票,无论哪里来的游客只有购票、检票后才能入园。现在有了二维码后,园区新增一个检票机,将二维码作为一种新的进景点的操作(对应访问者类),那么各类游客(对应访问角色类)可能用支付宝扫二维码,也可能使用微信扫二维码,这时二维码就是新的一个访问点。园区没有改变来访者,但是提供了一种新的操作,对于园区来说,不管你是什么身份的人,对他们来说都只是一个访问者而已。
接下来,我们再来看看 UML 对应的代码实现:
public interface Visitor {
void visitA(ElementA elementA);
void visitB(ElementB elementB);
//...
//void visitN(ElementN elementN);
}
public class VisitorBehavior implements Visitor {
@Override
public void visitA(ElementA elementA) {
int x = elementA.getAState();
x++;
System.out.println("=== 当前A的state为:"+x);
elementA.setAState(x);
}
@Override
public void visitB(ElementB elementB) {
double x = elementB.getBState();
x++;
System.out.println("=== 当前B的state为:"+x);
elementB.setBState(x