设计模式之非循环访问者模式 _ JAVA
非循环访问者模式从字面意思上能知道是基于访问者模式的一个改进版本,具体有哪些改进呢
访问者模式存在的问题
首先我们知道访问者模式所存在的问题:
访问者模式这种结构会在代码的依赖关系中形成一种循环依赖
也就是被访问层次结构,具体的接受访问(元素)的基类依赖于相应的访问者层次结构的基类
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仅在需要的时候才实现每个派生的访问方法
推荐阅读
-
php框架和设计模式区别
-
分析设计模式之模板方法Java实现
分析设计模式之模板方法Java实现目录一、什么是模板方法设计模式1.1、模板方法的用途1.2、模板方法的定义二、定义模板方...
-
观察者设计模式
观察者设计模式简介现实生活中,每个人都是一个观察者,同时也是一个被观察者,"你站在桥上看风景,看风景的人...
-
设计模式之访问者模式 _ JAVA
这个模式的基本想法:首先我们拥有一个由许多对象构成的对象结构,这些对象的类都拥有一个accept方法用来接受访问者对象;访问...
-
设计模式之适配器模式 _ JAVA
适配器模式对于大家来说算是比较常见的用的比较多的模式了,主要功能是将类的接口转换为客户期望的另一个接口,使用适配器避免了由于接口不...
-
php框架和设计模式区别
-
分析设计模式之模板方法Java实现
分析设计模式之模板方法Java实现目录一、什么是模板方法设计模式1.1、模板方法的用途1.2、模板方法的定义二、定义模板方...
-
观察者设计模式
观察者设计模式简介现实生活中,每个人都是一个观察者,同时也是一个被观察者,"你站在桥上看风景,看风景的人...
-
设计模式之访问者模式 _ JAVA
这个模式的基本想法:首先我们拥有一个由许多对象构成的对象结构,这些对象的类都拥有一个accept方法用来接受访问者对象;访问...
-
设计模式之适配器模式 _ JAVA
适配器模式对于大家来说算是比较常见的用的比较多的模式了,主要功能是将类的接口转换为客户期望的另一个接口,使用适配器避免了由于接口不...
-
php框架和设计模式区别
-
分析设计模式之模板方法Java实现
分析设计模式之模板方法Java实现目录一、什么是模板方法设计模式1.1、模板方法的用途1.2、模板方法的定义二、定义模板方...
-
观察者设计模式
观察者设计模式简介现实生活中,每个人都是一个观察者,同时也是一个被观察者,"你站在桥上看风景,看风景的人...
-
设计模式之访问者模式 _ JAVA
这个模式的基本想法:首先我们拥有一个由许多对象构成的对象结构,这些对象的类都拥有一个accept方法用来接受访问者对象;访问...
-
设计模式之适配器模式 _ JAVA
适配器模式对于大家来说算是比较常见的用的比较多的模式了,主要功能是将类的接口转换为客户期望的另一个接口,使用适配器避免了由于接口不...