设计模式之禅之设计模式-访问者模式

一:访问者模式定义
        --->封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

二:访问者模式角色

● Visitor——抽象访问者
        抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以被访问的。
● ConcreteVisitor——具体访问者
        它影响访问者访问到一个类后该怎么干,要做什么事情。
● Element——抽象元素
        接口或者抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的。
● ConcreteElement——具体元素
        实现accept方法,通常是visitor.visit(this),基本上都形成了一种模式了。
● ObjectStruture——结构对象
        元素产生者,一般容纳在多个不同类、不同接口的容器,如List、Set、Map等,在项目中,一般很少抽象出这个角色。

三:访问者模式的应用
【1】访问者模式的优点

● 符合单一职责原则
        具体元素角色也就是Employee抽象类的两个子类负责数据的加载,而Visitor类则负责报表的展现,两个不同的职责非常明确地分离开来,各自演绎变化。

● 优秀的扩展性
        由于职责分开,继续增加对数据的操作是非常快捷的,例如,现在要增加一份给大老板的报表,这份报表格式又有所不同,直接在Visitor中增加一个方法,传递数据后进行整理打印。

● 灵活性非常高
        不同的访问者不同的操作

【2】访问者模式的缺点
● 具体元素对访问者公布细节
         访问者要访问一个类就必然要求这个类公布一些方法和数据,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的。

● 具体元素变更比较困难
        具体元素角色的增加、删除、修改都是比较困难的,就上面那个例子,你想想,你要是想增加一个成员变量,如年龄age,Visitor就需要修改,如果Visitor是一个还好办,多个呢?业务逻辑再复杂点呢?

● 违背了依赖倒置转原则
        访问者依赖的是具体元素,而不是抽象元素,这破坏了依赖倒置原则,特别是在面向对象的编程中,抛弃了对接口的依赖,而直接依赖实现类,扩展比较难。

【3】访问者模式的应用场景
● 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作,也就说是用迭代器模式已经不能胜任的情景。
● 需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。
● 总结一下,在这种地方你一定要考虑使用访问者模式:业务规则要求遍历多个不同的对象。这本身也是访问者模式出发点,迭代器模式只能访问同类或同接口的数据(当然了,如果你使用instanceof,那么能访问所有的数据,这没有争论),而访问者模式是对迭代器模式的扩充,可以遍历不同的对象,然后执行不同的操作,也就是针对访问的对象不同,执行不同的操作。访问者模式还有一个用途,就是充当拦截器(Interceptor)角色,这个我们将在混编模式中讲解。

四:访问者模式中涉及的概念:双分派

---->说到访问者模式就不得不提一下双分派(double dispatch)问题,什么是双分派呢?我们先来解释一下什么是单分派(single dispatch)和多分派(multiple dispatch),
---->单分派:处理一个操作是根据请求者的名称和接收到的参数决定的,在Java中有静态绑定和动态绑定之说,它的实现是依据重载(overload)和覆写(override)实现的
---->重载在编译器期就决定了要调用哪个方法,它是根据role的表面类型而决定调用act(Role role)方法,这是静态绑定;而Actor的执行方法act则是由其实际类型决定的,这是动态绑定。
---->看到没?不管演员类和角色类怎么变化,我们都能够找到期望的方法运行,这就是双反派。双分派意味着得到执行的操作决定于请求的种类和两个接收者的类型,它是多分派的一个特例。从这里也可以看到Java是一个支持双分派的单分派语言。

五:访问者模式案例

【1】数据公共部分

 1 package com.yeepay.sxf.template20;
 2 /**
 3  * 数据公共部分
 4  * @author sxf
 5  *
 6  */
 7 public abstract class Employee {
 8     public final static int MALE=0;//0代表是男性
 9     public final static int FEMALE=1;//1代表是女性
10     //甭管是谁,都有工资
11     private String name;
12     //薪水
13     private int salary;
14     //性别很重要
15     private int sex;
16     //构造函数
17     public Employee(String name,int salary,int sex){
18         this.name=name;
19         this.salary=salary;
20         this.sex=sex;
21     }
22     /**
23      * 访问者访问内容
24      * @param iVisitor
25      */
26     public abstract void accept(IVisitor iVisitor);
27
28     //set get 方法
29     public String getName() {
30         return name;
31     }
32     public void setName(String name) {
33         this.name = name;
34     }
35     public int getSalary() {
36         return salary;
37     }
38     public void setSalary(int salary) {
39         this.salary = salary;
40     }
41     public int getSex() {
42         return sex;
43     }
44     public void setSex(int sex) {
45         this.sex = sex;
46     }
47
48 }

【2】员工数据

 1 package com.yeepay.sxf.template20;
 2 /**
 3  * 小兵(员工数据)
 4  * @author sxf
 5  *
 6  */
 7 public class CommonEmployee extends Employee {
 8     //工作内容
 9     private String job;
10     //构造函数
11     public CommonEmployee(String name, int salary, int sex, String job) {
12         super(name, salary, sex);
13         this.job = job;
14     }
15
16     /**
17      * 访问者实现
18      */
19     @Override
20     public void accept(IVisitor iVisitor) {
21         iVisitor.visit(this);
22     }
23
24
25     public String getJob() {
26         return job;
27     }
28     public void setJob(String job) {
29         this.job = job;
30     }
31
32
33
34 }

【3】管理层数据

 1 package com.yeepay.sxf.template20;
 2 /**
 3  * 管理者
 4  * @author sxf
 5  *
 6  */
 7 public class Manager extends Employee {
 8     //业绩
 9     private String refcestr;
10
11     //构造函数
12     public Manager(String name, int salary, int sex, String refcestr) {
13         super(name, salary, sex);
14         this.refcestr = refcestr;
15     }
16
17     /**
18      * 访问者访问
19      */
20     @Override
21     public void accept(IVisitor iVisitor) {
22         iVisitor.visit(this);
23     }
24
25
26     public String getRefcestr() {
27         return refcestr;
28     }
29
30     public void setRefcestr(String refcestr) {
31         this.refcestr = refcestr;
32     }
33
34
35 }

【4】访问者接口

 1 package com.yeepay.sxf.template20;
 2 /**
 3  * 访问者接口
 4  * @author sxf
 5  *
 6  */
 7 public interface IVisitor {
 8     //首先,定义我可以访问普通员工
 9     public void visit(CommonEmployee commonEmployee);
10     //其次,定义我还可以访问部门经理
11     public void visit(Manager manager);
12 }

【5】普通展示访问者实现

 1 package com.yeepay.sxf.template20;
 2 /**
 3  * 具体的访问者
 4  * @author sxf
 5  *
 6  */
 7 public class Visitor implements IVisitor {
 8
 9     //访问普通员工,打印出报表
10     @Override
11     public void visit(CommonEmployee commonEmployee) {
12         System.out.println(this.getCommonEmployee(commonEmployee));
13     }
14
15     @Override
16     public void visit(Manager manager) {
17         System.out.println(this.getManagerInfo(manager));
18     }
19     //组装出基本信息
20     private String getBasicInfo(Employee employee){
21     String info = "姓名:" + employee.getName() + "\t";
22     info = info + "性别:" +(employee.getSex() == Employee.FEMALE?"女":"男");
23     info = info + "薪水:" + employee.getSalary() + "\t";
24     return info;
25     }
26     //组装出部门经理的信息
27     private String getManagerInfo(Manager manager){
28     String basicInfo = this.getBasicInfo(manager);
29     String otherInfo = "业绩:"+manager.getRefcestr() + "\t";
30     return basicInfo + otherInfo;
31     }
32     //组装出普通员工信息
33     private String getCommonEmployee(CommonEmployee commonEmployee){
34     String basicInfo = this.getBasicInfo(commonEmployee);
35     String otherInfo = "工作:"+commonEmployee.getJob()+"\t";
36     return basicInfo + otherInfo;
37     }
38
39 }

【6】报表展示访问者的扩展接口

 1 package com.yeepay.sxf.template20;
 2 /**
 3  * 对访问者接口的扩展
 4  * 展示访问者的报表
 5  * @author sxf
 6  *
 7  */
 8 public interface IShowVisitor extends IVisitor{
 9     //展示报表
10     public void report();
11 }

【7】统计访问者的扩展接口

 1 package com.yeepay.sxf.template20;
 2 /**
 3  * 统计访问
 4  * @author sxf
 5  *
 6  */
 7 public interface ITotalVisitor extends IVisitor {
 8
 9     //统计所有员工的工资总和
10     public void totalSalary();
11 }

【8】报表展示访问者的扩展接口实现类

 1 package com.yeepay.sxf.template20;
 2 /**
 3  * 展示的访问者
 4  * @author sxf
 5  *
 6  */
 7 public class ShowVisitor implements IShowVisitor {
 8
 9     private String info="";
10
11     //组装出基本信息
12     private String getBasicInfo(Employee employee){
13     String info = "姓名:" + employee.getName() + "\t";
14     info = info + "性别:" +(employee.getSex() == Employee.FEMALE?"女":"男");
15     info = info + "薪水:" + employee.getSalary() + "\t";
16     return info;
17     }
18     //组装出部门经理的信息
19     private String getManagerInfo(Manager manager){
20     String basicInfo = this.getBasicInfo(manager);
21     String otherInfo = "业绩:"+manager.getRefcestr() + "\t";
22     return basicInfo + otherInfo;
23     }
24     //组装出普通员工信息
25     private String getCommonEmployee(CommonEmployee commonEmployee){
26     String basicInfo = this.getBasicInfo(commonEmployee);
27     String otherInfo = "工作:"+commonEmployee.getJob()+"\t";
28     return basicInfo + otherInfo;
29     }
30
31
32     @Override
33     public void visit(CommonEmployee commonEmployee) {
34         this.info=this.info+this.getBasicInfo(commonEmployee);
35     }
36
37     @Override
38     public void visit(Manager manager) {
39         this.info=this.info+this.getManagerInfo(manager);
40     }
41
42     /**
43      * 展示
44      */
45     @Override
46     public void report() {
47         System.out.println("ShowVisitor.report()"+this.info);
48     }
49
50
51 }

【9】统计访问者的扩展接口实现

 1 package com.yeepay.sxf.template20;
 2 /**
 3  * 统计访问者接口实现
 4  * @author sxf
 5  *
 6  */
 7 public class TotalVisitor implements ITotalVisitor{
 8     //管理层的工资系数
 9     private final static int MANAGER_COEFFICIENT=5;
10     //员工的工资系数
11     private final static int COMMONEMPLOYEE_COEFFICIENT=2;
12
13     //普通员工工资总和
14     private int commonTotalSalary=0;
15
16     //部门经历的工资总和
17     private int managerTotalSalary=0;
18
19     @Override
20     public void visit(CommonEmployee commonEmployee) {
21         this.commonTotalSalary=this.commonTotalSalary+commonEmployee.getSalary()*COMMONEMPLOYEE_COEFFICIENT;
22     }
23
24     @Override
25     public void visit(Manager manager) {
26         this.commonTotalSalary=this.commonTotalSalary+manager.getSalary()*MANAGER_COEFFICIENT;
27     }
28
29     @Override
30     public void totalSalary() {
31         System.out.println("TotalVisitor.totalSalary(工资总和为===>:)"+(commonTotalSalary+managerTotalSalary));
32     }
33
34
35 }

【10】测试类

 1 package com.yeepay.sxf.template20;
 2
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 /**
 6  * 访问者测试
 7  * 双分派测试
 8  * @author sxf
 9  *
10  */
11 public class ClientTest {
12
13     public static void main(String[] args) {
14         //test01();
15     //    test02();
16         test03();
17     }
18
19
20     //一个访问者测试
21     public static void test01(){
22         //数据
23         List<Employee> list=mockEmployee();
24         for(Employee mo:list){
25             mo.accept(new Visitor());
26         }
27     }
28
29
30
31
32     //多个访问者测试
33     public static void test02(){
34         //数据
35         List<Employee> list=mockEmployee();
36
37         //数据展示访问者
38         IShowVisitor showIVisitor=new ShowVisitor();
39         //工资计算访问者
40         ITotalVisitor totalVisitor=new TotalVisitor();
41
42         for(Employee employee:list){
43             employee.accept(showIVisitor);
44             employee.accept(totalVisitor);
45         }
46
47         //数据展示
48         showIVisitor.report();
49         //工资计算
50         totalVisitor.totalSalary();
51     }
52
53
54     //制造员工集合
55     public static List<Employee> mockEmployee(){
56         List<Employee> list=new ArrayList<Employee>();
57         CommonEmployee bin1=new CommonEmployee("sxf", 15000, 1, "java开发");
58         CommonEmployee bin2=new CommonEmployee("sxs", 15000, 1, ".net开发");
59         CommonEmployee bin3=new CommonEmployee("sxy", 15000, 0, "前端开发");
60         Manager manager1=new Manager("aaaaaaa", 100000, 0, "怕啊啊");
61         Manager manager2=new Manager("bbbbbb", 100000, 0, "公官");
62         list.add(bin1);
63         list.add(bin2);
64         list.add(bin3);
65         list.add(manager1);
66         list.add(manager2);
67         return list;
68     }
69
70
71     //测试双分派
72     public static void test03(){
73         //重载,看参数类型
74         //重写,看调用者类型
75         AbsActor absActor=new OldActor();
76         Role role=new KongFuRole();
77         KongFuRole role2=new KongFuRole();
78         absActor.act(role);
79         absActor.act(role2);
80
81         AbsActor absActor2=new YongActor();
82         absActor2.act(role);
83         absActor2.act(role2);
84     }
85 }

【11】双分派
 [1]角色

 1 package com.yeepay.sxf.template20;
 2 /**
 3  * 角色
 4  * @author sxf
 5  *
 6  */
 7 public interface Role {
 8     //演员要扮演的角色
 9 }
10
11
12 package com.yeepay.sxf.template20;
13 /**
14  * 功夫角色
15  * @author sxf
16  *
17  */
18 public class KongFuRole implements Role{
19
20 }
21
22 package com.yeepay.sxf.template20;
23 /**
24  * 白痴角色
25  * @author sxf
26  *
27  */
28 public class IdiotRole implements Role{
29
30 }

[2]演员

 1 package com.yeepay.sxf.template20;
 2 /**
 3  * 抽象演员
 4  * @author sxf
 5  *
 6  */
 7 public abstract class AbsActor {
 8
 9     public void act(Role role){
10         System.out.println("AbsActor.act(演员可以演所有角色)");
11     }
12
13     public void act(KongFuRole kongFuRole){
14         System.out.println("AbsActor.act(演员可以演功夫角色)");
15     }
16 }
17
18
19 package com.yeepay.sxf.template20;
20 /**
21  * 年龄大的演员
22  * @author sxf
23  *
24  */
25 public class OldActor extends AbsActor{
26     //不演功夫角色
27     @Override
28     public void act(KongFuRole kongFuRole){
29         System.out.println("OldActor.act(年龄老的演员不能演功夫角色)");
30     }
31 }
32
33
34 package com.yeepay.sxf.template20;
35 /**
36  * 年轻演员
37  * @author sxf
38  *
39  */
40 public class YongActor extends AbsActor{
41
42     //年轻演员最喜欢演功夫戏
43     public void act(KongFuRole kongFuRole){
44         System.out.println("YongActor.act(年轻演员最喜欢演功夫角色)");
45     }
46 }

时间: 2024-08-25 05:10:26

设计模式之禅之设计模式-访问者模式的相关文章

设计模式解密(22)- 访问者模式 - 扩展篇(分派的概念)

前言:访问者模式拆分  访问者模式基础篇 :http://www.cnblogs.com/JsonShare/p/7380772.html  访问者模式扩展篇 - 分派的概念: http://www.cnblogs.com/JsonShare/p/7381705.html 1.分派的概念 变量被声明时的类型叫做变量的静态类型(Static Type),有些人又把静态类型叫做明显类型(Apparent Type):而变量所引用的对象的真实类型又叫做变量的实际类型(Actual Type).比如:

设计模式之第20章-访问者模式(Java实现)

设计模式之第20章-访问者模式(Java实现) “嘿,你脸好红啊.”“精神焕发.”“怎么又黄了?”“怕冷,涂的,涂的,蜡.”“身上还有酒味,露馅了吧,原来是喝酒喝的啊.”“嘿嘿,让,让你发现了,今天来几个朋友,然后就小聚一下,小饮,几杯啦.”“小日子过得不错嘛.”“那是自然,要不然,再去喝两杯.”“别介,我还有要事要做呢,鱼哥你别坑我.”“什么,什么要紧事,能比的上,喝酒啊”.“走,陪我,陪我喝两杯去.”(作者已被拉走.)访问者登场. 访问者模式之自我介绍 累的死俺的杰特们(ladies and

设计模式 ( 二十一 ):Vistor访问者模式 -- 行为型

1.概述 在软件开发过程中,对于系统中的某些对象,它们存储在同一个集合collection中,且具有不同的类型,而且对于该集合中的对象,可以接受一类称为访问者的对象来访问,而且不同的访问者其访问方式有所不同. 例子1:顾客在超市中将选择的商品,如苹果.图书等放在购物车中,然后到收银员处付款.在购物过程中,顾客需要对这些商品进行访问,以便确认这些商品的质量,之后收银员计算价格时也需要访问购物车内顾客所选择的商品. 此时,购物车作为一个ObjectStructure(对象结构)用于存储各种类型的商品

Java 设计模式系列(二三)访问者模式(Vistor)

Java 设计模式系列(二三)访问者模式(Vistor) 访问者模式是对象的行为模式.访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变. 一.访问者模式结构 访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化. 数据结构的每一个节点都可以接受一个访问者的调用,此节点向访问者对象传入节点对象,而访问者对象则反过来执行节点对象的操作.这样的过程叫做"双重分派

23种设计模式(9):访问者模式(转)

定义:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作. 类型:行为类模式 类图: 访问者模式可能是行为类模式中最复杂的一种模式了,但是这不能成为我们不去掌握它的理由.我们首先来看一个简单的例子,代码如下: 1 class A { 2 public void method1(){ 3 System.out.println("我是A"); 4 } 5 6 public void method2(B b){ 7 b.showA(this)

23种设计模式(9):访问者模式

定义:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作. 类型:行为类模式. 类图: 访问者模式可能是行为类模式中最复杂的一种模式了,但是这不能成为我们不去掌握它的理由.我们首先来看一个简单的例子,代码如下: class A { public void method1(){ System.out.println(“我是A”); } public void method2(B b){ b.showA(this); } } class B { pu

设计模式@第18章:访问者模式

第18章:访问者模式 一.测评系统的需求 完成测评系统需求 将观众分为男人和女人,对歌手进行测评,当看完某个歌手表演后,得到他们对该歌手不同的评价(评价 有不同的种类,比如 成功.失败 等) 传统方案 二.传统方式的问题分析 如果系统比较小,还是 ok 的,但是考虑系统增加越来越多新的功能时,对代码改动较大,违反了 ocp 原则, 不利于维护 扩展性不好,比如 增加了 新的人员类型,或者管理方法,都不好做 引出我们会使用新的设计模式 – 访问者模式 三.访问者模式基本介绍 访问者模式(Visit

Java设计模式菜鸟系列(二十三)访问者模式建模与实现

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/40028509 访问者模式(Visitor):把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化.访问者模式适用于数据结构相对稳定而算法又容易变化的系统.访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者:而它的缺点就是增加新的数据结构很困难. 一.uml建模: 二.代码实现 /** * 访问者模式(Visitor):把数据结构和作用于结构上的操作解耦合,使

设计模式解密(22)- 访问者模式

前言:访问者模式拆分  访问者模式基础篇 :http://www.cnblogs.com/JsonShare/p/7380772.html  访问者模式扩展篇 - 分派的概念: http://www.cnblogs.com/JsonShare/p/7381705.html 1.简介  定义:表示一个作用于其对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作. 主要解决:稳定的数据结构和易变的操作耦合问题.就是把数据结构和作用于结构上的操作解耦合,使得操作集合可