封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
先建一个元素接口IPerson,定义一个方法accept ,为了让访问者能访问到自己
public interface IPersonService {
void accept(IVisitorService action);
String getName();
}
public class Man implements IPersonService {
@Override
public void accept(IActionService action) {
action.visitor(this);
}
@Override
public String getName() {
return "Man";
}
}
public class Women implements IPersonService {
@Override
public void accept(IActionService action) {
action.visitor(this);
}
@Override
public String getName() {
return "Women";
}
}
public interface IVisitorService {
void visitorMan(Man man);
void visitorWomen(Women man);
}
public class Visitor1 implements IVisitorService {
@Override
public void visitorMan(Man man) {
System.out.println("Visitor1 " + man.getName());
}
@Override
public void visitorWomen(Women woman) {
System.out.println("Visitor1 " + woman.getName());
}
}
public class Visitor2 implements IVisitorService {
@Override
public void visitorMan(Man man) {
System.out.println("Visitor2 " + man.getName());
}
@Override
public void visitorWomen(Women man) {
System.out.println("Visitor2 " + man.getName());
}
}
public class ObjectStructure {
List list = Lists.newArrayList();
/**
* 增加
*
* @param action
*/
void add(IPersonService action) {
this.list.add(action);
}
/**
* 移除
*
* @param action
*/
void remove(IPersonService action) {
this.list.remove(action);
}
/**
* @param action
*/
public void display(IVisitorService action) {
list.stream().forEach(e -> {
e.accept(action);
});
}
}
6 测试一下,建个client:
public class client {
public static void main(String[] args) {
ObjectStructure obj = new ObjectStructure();
obj.add(new Man());
obj.add(new Women());
Visitor1 v1 = new Visitor1();
obj.display(v1);
Visitor2 v2 = new Visitor2();
obj.display(v2);
}
}
上面也说了,增加元素时比较麻烦嘛,设计模式的书里也提到过有一定的现在,这里可以用反射的方式,根据具体的元素执行具体的方法嘛(
参照文章
参考的这边文章 https://www.javaworld.com/article/2077602/java-tip-98--reflect-on-the-visitor-design-pattern.html)
思路:接口里面增加一个visit 方法,根据具体的类型,调用具体的执行方法,代码如下:
public interface IVisitorService {
void visitorMan(Man man);
void visitorWomen(Women man);
/**
* 这里是通过反射,选择具体的执行方法
* @param obj
*/
void visitor(Object obj);
}
具体的visitor 1(visitor2 类的代码就不贴了,和 visitor1 一样的) (敲黑板,划重点,这是匹配规则时,用了一个visitor 作为前缀,这里需要统一一个命名规则)如下:
public class Visitor1 implements IVisitorService {
public void visitorMan(Man man) {
System.out.println("Visitor1 " + man.getName());
}
public void visitorWomen(Women woman) {
System.out.println("Visitor1 " + woman.getName());
}
@Override
public void visitor(Object obj) {
String className = obj.getClass().getName();
String methodName = "visitor" + className.substring(className.lastIndexOf(".") + 1);
try {
Method method = getClass().getMethod(methodName, new Class>[] {obj.getClass()});
method.invoke(this, new Object[]{obj});
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
接下来所有的 元素里面的accept ,调用的是 visit() 方法:
public class Man implements IPersonService {
@Override
public void accept(IVisitorService action) {
action.visitor(this);
}
@Override
public String getName() {
return "Man";
}
}
小结一下:这样就可以解决,增加元素时IVisitor 里面类型定死的问题了,直接在实现类里面定义即可。
我感觉 在接口里面定义一个 visitor 方法,每一个实现类都需要实现,只要遵循规则,感觉每次都要实现太麻烦了,所以我提出再抽出一个 基础类,把visitor(Object obj) 方法放在里面,如果需要改动,也可以在实现类里面重写,如果不需要,直接默认使用
public abstract class BaseAction implements IVisitorService{
public void visitor(Object obj) {
String className = obj.getClass().getName();
String methodName = "visitor" + className.substring(className.lastIndexOf(".") + 1);
try {
Method method = getClass().getMethod(methodName, new Class>[] {obj.getClass()});
method.invoke(this, new Object[]{obj});
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
具体的访问者只要继承 BaseAction 即可,其他不用动。如下为 Visitor1 的代码(Visitor2 代码几乎一样),这样一看,都简洁
public class Visitor1 extends BaseAction{
public void visitorMan(Man man) {
System.out.println("Visitor1 " + man.getName());
}
public void visitorWomen(Women woman) {
System.out.println("Visitor1 " + woman.getName());
}
}
到此,访问者设计模式 梳理差不多了,如果有哪里对不,请指出,谢谢。