Visitor Pattern 访问者模式是的定义如下:
Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
封装一些作用于某种数据接口中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
访问者模式中的几个角色:
1,Visitor -- 抽象访问接口
声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以访问的。
2,ConcreteVisitor -- 具体访问者
3,Element -- 抽象元素
接口或者抽象类,声明接受哪一类访问者访问,程序上通过accept方法参数去定义
4,ConcreteElement -- 具体元素
实现accept方法,通常是vistor.visit(this),基本上就形成了一种模式了。
5,ObjectStructure -- 结构对象
远程产生者,一般容纳多个不同类、不同接口的容器,如List、Set、Map等,在项目中,一般很少抽象出这个角色。
通用源码:
public abstract class Element { // 定义业务逻辑 public abstract void doSomething(); // 允许谁来访问 public abstract void accept(IVisitor visitor); }
public class ConcreteElement1 extends Element { @Override public void doSomething() { System.out.println("do1..."); } @Override public void accept(IVisitor visitor) { visitor.visit(this); } }
public class ConcreteElement2 extends Element { @Override public void doSomething() { System.out.println("do2..."); } @Override public void accept(IVisitor visitor) { visitor.visit(this); } }
public interface IVisitor { // 可以访问哪些对象 public void visit(ConcreteElement1 element1); public void visit(ConcreteElement2 element2); }
public class Visitor implements IVisitor { @Override public void visit(ConcreteElement1 element1) { element1.doSomething(); } @Override public void visit(ConcreteElement2 element2) { element2.doSomething(); } }
public class Client { public static void main(String[] args) { for (int i = 0; i < 10; i++) { if (i % 2 == 0) { new ConcreteElement1().accept(new Visitor()); } else { new ConcreteElement2().accept(new Visitor()); } } } }
访问者模式的优点:
1,符合单一职责原则
具体元素角色Element抽象类的两个子类负责数据的加载,而Visitor类则负责报表的展现,两个具体不同的职责非常明确的分开了,各自演绎变化
2,优先的扩展性
由于职责分开,继续增加数据的操作非常快捷,比如要增加一份给大boss的报表,这份报表格式又有所不同,我们只需要在Visitor中增加一个方法,传递数据后整理打印出来即可,原来的Element不动。
3,灵活性非常高
比如那个Employee的例子,如果要统计所有人的奖金,计算规则是员工工资*0.4,部门经理工资*0.6,总经理的工资*0.8,之前我们怎么做的?那么对所有Employee进行循环,然后用instanceof来判断,我勒个擦,太不优美了,这时候用访问者模式就可以完美解决了,把数据扔给访问者,由访问者来统计计算。
访问者模式的缺点:
1,具体的元素Element对访问者公布细节
2,具体元素变更比较困难
3,违背了依赖倒置原则
访问者访问的是具体元素,而不是抽象元素,这破坏了依赖倒置原则,扩展比较困难。
访问者模式的使用场景:
1,一个对象结构包含很多类对象,它们有不同的接口,比如上面的Employee的子类有普通员工和经理等。而你想对这些对象实施一些依赖于其具体实现类的操作,也就是说用迭代器模式已经不能胜任了,因为你还得去用instanceof去判断类型,囧。
2,需要对一个对象结构(一般来讲是集合)中的对象进行很多次不同并且不相关的操作,而你想避免让这些操作污染这些类对象。
3,访问者模式还可以充当拦截器Interceptor角色使用。
访问者模式的扩展:
统计功能:
统计报表是我们经常需要实现的功能,基本上都是一堆计算公式,然后出一个报表,很多项目采用了数据库的存储过程实现,不过这是不推荐的做法。除非海量数据,一晚上要处理上亿、几十亿条数据,除了存储过程来处理还没有其他办法。
public interface IVistor { // 首先定义我可以访问普通员工 public void visit(CommonEmployee commonEmp); // 其次还定义我可以访问部门经理 public void visit(Manager manager); // 统计所有员工的工资总和 public int getTotalSalary(); } public class Visitor implements IVisitor { // 部门经理的系数是5 private final int managerRatio = 5; // 普通员工的系数是3 private final int commonRatio = 3; // 普通员工的工资总和 private int commmonTotal = 0; // 经理工资总和 private int managerTotal = 0; private void calManager(int salary) { managerTotal += salary*managerRatio; } private void calCommon(int salary) { commmonTotal += salary*commonRatio; } public int getTotalSalary() { return managerTotal + commmonTotal; } public void visit(CommonEmployee commonEmp) { System.out.println("哥访问的是普通的员工"); calCommon(commonEmp.getSalary()); } public void visit(Manager manager) { System.out.println("哥访问的是经理"); calManager(manager.getSalary()); } } public class Client { public static void main(String[] args) { IVisitor vistor = new Visitor(); List<Employee> list = null; for (Employee emp : list) { emp.accept(visitor); } System.out.println("工资总和:" + vistor.getTotalSalary()); } }
多个访问者:
上面的其实应该分成两个访问者的,一个是仅仅用来展示数据的report的visitor,而另一个是负责汇总的total的visitor。可以增加两个接口,都继承自IVisitor,但是各自有自己的方法。最后循环中调用
emp.accept(reportVisitor);
emp.accept(totalVisitor); 让所有信息在Visitor实例中积累起来。
然后最后面的时候,就可以直接调用各自的方法了。
双分派问题:
public interface Role { public void accept(AbsActor actor); }
public class UglyRole implements Role { @Override public void accept(AbsActor actor) { actor.act(this); } }
public class BeautyRole implements Role { @Override public void accept(AbsActor actor) { actor.act(this); } }
public class Client { public static void main(String[] args) { // 定义一个演员 AbsActor actor = new UglyActor(); // 定义一个角色 Role role = new BeautyRole(); // // 开始演戏 // actor.act(role); // // 动态绑定 // actor.act(new BeautyRole()); // 开始演戏(访问者模式) role.accept(actor); } }
本人博客已搬家,新地址为:http://yidao620c.github.io/
相关推荐
设计模式C++学习之访问者模式(Visitor)
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段...
访问者模式,你绝对会用到的模式,值得学习,通俗易懂的实例,原理和运用都说明白了。
java设计模式之访问者模式,通过实际例子说明访问者模式原理和适用场景;
设计模式之访问者模式Java版本的实现和UML类图
ios 平台实现设计模式-访问者模式,以最简单的代码实现访问者模式讲解,主旨在于了解访问者模式,博客:http://blog.sina.com.cn/s/blog_161d504630102wwxe.html
设计模式 - 访问者模式
最简单的访问者模式讲解代码,设计模式可看看博客中简介http://blog.sina.com.cn/s/blog_161d504630102wxis.html
访问者模式(Visitor Pattern)是一种行为型设计模式,旨在不改变被访问对象结构的情况下,定义对其元素的新操作。访问者模式通过将操作封装在独立的类中,使得新的操作可以灵活地添加,而无需修改对象的结构。访问...
设计模式-访问者模式(讲解及其实现代码)
C#面向对象设计模式纵横谈(24):(行为型模式) Visitor 访问者模式
设计模式主要分为三大类: 1.创建型模式:工厂模式、抽象...4.行为型模式:模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。
c++设计模式-行为型模式-访问者模式;qt工程;c++简单源码; 访问者(Visitor)模式的定义:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新...
5.11 visitor(访问者)—对象行为型 模式 218 5.12 行为模式的讨论 228 5.12 1 封装变化 228 5.12.2 对象作为参数 228 5.12.3 通信应该被封装还是被分布 229 5.12.4 对发送者和接收者解耦 229 5.12.5 总结 ...
设计模式的访问者模式的例子,希望对大家有用~~~~~~~~
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 其实还有两类:并发型模式和线程池模式。
java 设计模式之访问者模式.rarjava 设计模式之访问者模式.rar
访问者模式(Visitor) 用意:适用于数据结构相对未定的系统,把数据结构和作用于结构上的操作间的耦合解开。
PPT内容包括:内附代码,实例,方便理解。 继承、封装、多态、UML 设计模式02 设计模式03-创建型模式 ...设计模式16-策略模式、模板方法、访问者 此PPT实例便于理解,对于深入理解OO思想有很大帮助。