非循环访问者模式从字面意思上能知道是基于访问者模式的一个改进版本,具体有哪些改进呢
访问者模式存在的问题
首先我们知道访问者模式所存在的问题:
访问者模式这种结构会在代码的依赖关系中形成一种循环依赖
也就是被访问层次结构,具体的接受访问(元素)的基类依赖于相应的访问者层次结构的基类
Visitor基类对于元素基类的每一个子类都有相应的接口方法,因此Visitor类依赖于元素的每个子类,当然也会有元素的每一个子类都依赖于元素。
这种依赖关系在实际应用中可能会有许多麻烦,每当创建一个新的子类元素时,必须更改Visitor类,由于元素依赖于访问者因此必须重新编写依赖于元素的每个模块,也就是说必须重新编写元素的每个子类
访问者模式的另一个问题,需要在访问者的每个子类中处理元素的每个子类的访问方法,即使不需要处理元素的每个子类访问方法
那么非循环访问者模式除了改进了访问者模式中的问题外有哪些优缺点呢?
非循环者访问模式的优点
没有了层次结构之间的循环依赖如果新增一个访问者,不需要重新编译所有访问者如果类层次结构中有新成员,则不会导致现有访问者的编译失败
非循环者访问模式的缺点
违反了软件设计的最小意外原则,里式替换原则,显示它可以传递任何访问者,但实际上只对特定的访问者感兴趣。必须为可访问类层次结构中的所有成员创建访问者的并行层次结
一个实例
移动电话的抽象类
public abstract class MobilePhone {
public abstract void accept(MobilePhoneVisitor mpVisitor);
}
移动电话Visitor接口,不包含任何方法,不依赖于被访问的层次结构用于子类在其自己的访问者中声明
public interface MobilePhoneVisitor {
// 所有访问者的基类
}
摄像头服务类,只接受特定的访问者
public class Camera extends MobilePhone {
private static final Logger LOGGER = LoggerFactory.getLogger(Camera.class);
@Override
public void accept(MobilePhoneVisitor mpVisitor) {
if (mpVisitor instanceof CameraVisitor) {
((CameraVisitor) mpVisitor).visit(this);
} else {
LOGGER.info("只有 CameraVisitor 被允许访问 [摄像头] 服务");
}
}
@Override
public String toString() { return " camera "; }
}
摄像头访问者接口,继承自移动电话访问者接口
public interface CameraVisitor extends MobilePhoneVisitor {
void visit(Camera camera);
}
闪光灯服务类,只接受特定的访问者
public class Flashlight extends MobilePhone {
private static final Logger LOGGER = LoggerFactory.getLogger(Flashlight.class);
@Override
public void accept(MobilePhoneVisitor mpVisitor) {
if (mpVisitor instanceof FlashlightVisitor) {
((FlashlightVisitor) mpVisitor).visit(this);
} else {
LOGGER.info("只有 FlashlightVisitor 被允许访问 [闪光灯] 服务");
}
}
@Override
public String toString() { return " flashlight "; }
}
闪光灯访问者接口,继承自移动电话访问者接口
public interface FlashlightVisitor extends MobilePhoneVisitor {
void visit(Flashlight flashlight);
}
具有照相功能的函数,需要摄像头和闪光灯同时提供服务
public class PhotographVisitor implements CameraVisitor, FlashlightVisitor {
private static final Logger LOGGER = LoggerFactory.getLogger(PhotographVisitor.class);
@Override
public void visit(Camera camera) {
LOGGER.info("The "+ camera + " is taking pictures");
}
@Override
public void visit(Flashlight flashlight) {
LOGGER.info("Flashing light");
}
}
视频通话函数,需要摄像头提供服务
public class VideoCallVisitor implements CameraVisitor {
private static final Logger LOGGER = LoggerFactory.getLogger(VideoCallVisitor.class);
@Override
public void visit(Camera camera) {
LOGGER.info("The " + camera + " is working");
}
}
非循环访问者模式允许将新的函数添加到现有类层次结构,并且不通过使访问者基类退化来创建GoF访问者模式固有的依赖循环。
public class App {
public static void main(String[] args) {
VideoCallVisitor vcv = new VideoCallVisitor();
PhotographVisitor pv = new PhotographVisitor();
Flashlight flashlight = new Flashlight();
Camera camera = new Camera();
flashlight.accept(vcv); // 闪光灯接受视频通话访问者
camera.accept(vcv); // 摄像头接受视频通话访问者
flashlight.accept(pv); // 闪光灯接受拍照访问者
camera.accept(pv); // 摄像头接受拍照访问者
}
}
在这个例子中,访问者基类是MobilePhoneVisitor,被访问层次结构的基类是 MobilePhone,它有两个子类 Camera 、Flashlight 。
每个子类都有自己的访问者接口 CameraVisitor 和 FlashlightVisitor。
VideoCallVisitor、PhotographVisitor仅在需要的时候才实现每个派生的访问方法