访问者模式
访问者模式:把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统数据结构,适用于数据结构相对稳定算法又易变化的系统
- 优点是增加操作很容易,因为增加操作意味着增加新的访问者
- 缺点就是增加新的数据结构很困难
UML
Java
- 定义访问者接口Vistor(操作):
public interface Visitor { void visit(Subject sub); }
- 定义被访问者Subject(数据结构),通过增加不同的Vistor,调用accept方法可达到动态添加新的操作
public abstract class Subject { public void accept(Visitor visitor) { visitor.visit(this); } public abstract String getSubject(); }
- 实现不同的Subject类:
public class MySubject1 extends Subject { @Override public String getSubject() { return "subject1"; } } public class MySubject2 extends Subject { @Override public String getSubject() { return "subject2"; } }
- 实现不同的Vistor类:
public class MyVisitor1 implements Visitor { @Override public void visit(Subject sub) { System.out.println("visitor1 visits the " + sub.getSubject()); } } public class MyVisitor2 implements Visitor{ @Override public void visit(Subject sub) { System.out.println("visitor2 visit the " + sub.getSubject()); } }
- 测试代码:
public class VisitorTest { public static void main(String[] args) { Visitor visitor = new MyVisitor1(); Subject sub = new MySubject1(); sub.accept(visitor); sub = new MySubject2(); sub.accept(visitor); visitor = new MyVisitor2(); sub = new MySubject1(); sub.accept(visitor); sub = new MySubject2(); sub.accept(visitor); } }
- 测试结果:
visitor1 visits the subject1 visitor1 visits the subject2 visitor2 visit the subject1 visitor2 visit the subject2
CLOS:
- 使用generic函数,无须定义Vistor数据结构:
;; 数据结构 (defclass subject () ((name :accessor name))) (defclass subject1 (subject) ((name :initform 'subject1))) (defclass subject2 (subject) ((name :initform 'subject2))) ;; 不同的操作 (defmethod op1 ((sub subject1)) (format nil "visitor1 visits the ~A " (name sub))) (defmethod op1 ((sub subject2)) (format nil "visitor1 visits the ~A " (name sub))) (defmethod op2 ((sub subject1)) (format nil "visitor2 visits the ~A " (name sub))) (defmethod op2 ((sub subject2)) (format nil "visitor2 visits the ~A " (name sub)))
- 测试结果:
(op1 (make-instance 'subject1)) ;; => "visitor1 visits the SUBJECT1 " (op1 (make-instance 'subject2)) ;; => "visitor1 visits the SUBJECT2 " (op2 (make-instance 'subject1)) ;; => "visitor2 visits the SUBJECT1 " (op2 (make-instance 'subject2)) ;; => "visitor2 visits the SUBJECT2 "