什么是访问者模式
封装一些作用于某种数据结构中各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新操作。
这是最后一个模式了,不知不觉也快要结束了。访问者模式也是这23种模式中最为晦涩的一个了,还好使用频率并不是很高。
访问者模式的适用场景
对象结构稳定,需要频繁在此对象基础上定义新操作
需要对对象内的数据操作,并不希望操作时对原对象有所影响
访问者模式用例
说一个关于我们这些将毕业的学生的例子吧。毕业求职,即渴望又害怕,安逸的生活就要切入风雨中了,哈哈,怕并没有什么用。某公司招聘Android开发和JavaWeb开发岗位的工程师,这不是重点,重点是面试或者笔试后,公司要归纳出一份表,顺序罗列出意向大的人员信息。根据需求分了两个方向:CEO需要看到面试者的综合素质的评定,CTO需要看到面试者的技术能力的评定,我们需要做的就是根据CEO或者CTO来分别划分需要的信息
UML类图:
AbsDeveloper类:
public abstract class AbsDeveloper {
public String name;
public String skill;
public String quality;
public AbsDeveloper(String name,String skill,String quality){
this.name = name;
this.skill = skill;
this.quality = quality;
}
public abstract void accept(IVisitor visitor);
}
AndroidDeveloper类:
public class AndroidDeveloper extends AbsDeveloper {
public AndroidDeveloper(String name, String skill, String quality) {
super(name, skill, quality);
// TODO Auto-generated constructor stub
}
@Override
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}
JavaWebDeveloper类:
public class JavaWebDeveloper extends AbsDeveloper {
public JavaWebDeveloper(String name, String skill, String quality) {
super(name, skill, quality);
// TODO Auto-generated constructor stub
}
@Override
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}
IVisitor接口:
public interface IVisitor {
public void visit(AndroidDeveloper android);
public void visit(JavaWebDeveloper web);
}
CEOVisitor实现类:
public class CEOVisitor implements IVisitor {
@Override
public void visit(AndroidDeveloper android) {
System.out.println("姓名:"+android.name+",综合素质:"+android.quality);
}
@Override
public void visit(JavaWebDeveloper web) {
System.out.println("姓名:"+web.name+",综合素质:"+web.quality);
}
}
CTOVisitor实现类:
public class CTOVisitor implements IVisitor {
@Override
public void visit(AndroidDeveloper android) {
System.out.println("姓名:"+android.name+",技能等级:"+android.skill+" ");
}
@Override
public void visit(JavaWebDeveloper web) {
System.out.println("姓名:"+web.name+",技能等级:"+web.skill+" ");
}
}
测试类:
public class Test {
public static void main(String[] args) {
//新建一份求职者列表,并载入评测成绩
List<AbsDeveloper> mCandidate = new LinkedList<>();
mCandidate.add(new AndroidDeveloper("张三","1,善于图像处理","为人正直,踏实能干"));
mCandidate.add(new JavaWebDeveloper("李四","2,善于网络开发","专心致志,可以考虑"));
mCandidate.add(new AndroidDeveloper("王五","2,善于开发文档维护","思路奇特,喜欢尝试"));
mCandidate.add(new JavaWebDeveloper("老刘","3,善于使用框架","善于言谈,喜欢聊天"));
mCandidate.add(new AndroidDeveloper("张飞","4,善于流行技术学习","一心一意做技术,不善于聊天"));
System.out.println("--------------CEO看到的表,突出综合素质------------");
for(AbsDeveloper developer:mCandidate){
developer.accept(new CEOVisitor());
}
System.out.println("--------------CTO看到的表,突出技术能力--------------");
for(AbsDeveloper developer:mCandidate){
developer.accept(new CTOVisitor());
}
}
}
运行结果:
--------------CEO看到的表,突出综合素质------------
姓名:张三,综合素质:为人正直,踏实能干
姓名:李四,综合素质:专心致志,可以考虑
姓名:王五,综合素质:思路奇特,喜欢尝试
姓名:老刘,综合素质:善于言谈,喜欢聊天
姓名:张飞,综合素质:一心一意做技术,不善于聊天
--------------CTO看到的表,突出技术能力--------------
姓名:张三,技能等级:1,善于图像处理
姓名:李四,技能等级:2,善于网络开发
姓名:王五,技能等级:2,善于开发文档维护
姓名:老刘,技能等级:3,善于使用框架
姓名:张飞,技能等级:4,善于流行技术学习
访问者模式总结:
访问者模式讲究根据需求来设计类,以上我们根据查看表不同席位的需求,拆分设计了CEO和CTO分别对应的Visitor类,对于原数据我们并没有做任何更改,只是根据需求自定义了筛选操作。其实相对于访问数据库来说,我们只需要添加一个条件查询就可以实现这么多代码实现的功能,这也是为什么这个模式不常用的原因,但是并不是没有用,真正你要用的时候,那是你真的需要用了。
优点:角色职务解耦,扩展性高,灵活易变。
缺点:对访问者公布代码细节,违反迪米特原则。具体元素修改代价巨大,比如现在要想添加性别、年龄到属性中,要改的可就太多了。依赖了具体的类。