访问者模式
首先
抽象员工
public abstract class Employee{
// 代表男性
public final static int MALE = 0;
// 代表女性
public final static int FEMALE = 1;
// 有工资
private String name;
// 薪水
private int salary;
// 性别
private int sex;
// get/set
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getSalary(){
return salary;
}
public void setSalary(int salary){
this.salary = salary;
}
public int getSex(){
return sex;
}
public void setSex(int sex){
this.sex = sex;
}
// 员工信息输出
public final void report(){
String info = "姓名" + this.name + "\t";
info = info + "性别" + this.sex + "\t";
info = info + "薪水" + this.salary + "\t";
info = info + this.getOtherinfo();
System.out.println(info);
}
// 拼装
protected abstract String getOtherinfo();
}
下面是普通员工
public class CommonEmployee extends Employee{
// 工作内容
private String job;
public String getJob(){
return job;
}
public void setJob(String job){
this.job = job;
}
protected String getOtherinfo(){
return "工作: " + this.job + "\t";
}
}
管理层
public class Manager extends Employee{
// 职责
private String performance;
public String getPerformance(){
return performance;
}
public void setPerformance(String performance){
this.performance = performance;
}
protected String getOtherinfo(){
return "业绩" + this.performance + "\t";
}
}
最后场景
public class Client{
public static void main(String[] args){
for(Employee emp:mockEmployee()){
emp.report();
}
}
public static List mockEmployee(){
List empList = new ArrayList();
// 产生员工
CommonEmployee zhangSan = new CommonEmployee();
zangSan.setJon("编写程序");
zangSan.setName("张三");
zangSan.setSalary(1800);
zangSan.setSex(Employee.MALE);
empList.add(zangSan);
// 产生员工
CommonEmployee liSi = new CommonEmployee();
liSi.setJob("美工");
liSi.setName("李四");
liSi.setSalary(1900);
liSi.setSex(Employee.FEMALE);
empList.add(liSi);
// 产生经理
Manage wangWu = new Manger();
wangWu.setName("王五");
wangWu.setPerformance("负值");
wangWu.setSalary(18750);
wangWu.setSex(Employee.MALE);
empList.add(wangWu);
return empList;
}
}
改造如下
先定义访问者接口
public interface IVisitor{
// 定义普通员工
public void vsit(CommonEmployee commonEmployee);
// 定义访问部门经理
public void visit(Manager manager);
}
访问者实现
public class Visitor implements IVisitor{
// 访问普通员工,打印报表
public void visit(CommonEmployee commonEmployee){
System.out.println(this.getCommonEmployee(commonEmployee));
}
// 访问部门经理
public void visit(Manager manager){
System.out.println(this.getManagerinfo(manager));
}
// 组装基本信息
private String getBasicinfo(Employee employee){
String info = "姓名" + employee.getName() + "\t";
info = info + "性别" + (employee.getSex() == Employee.FEMALE?"女","男");
info = info + "薪水" + employee.getSalary() + "\t";
return info;
}
// 组装普通员工信息
private String getCommonEmployee(CommonEmployee commonEmployee){
String basicinfo = this.getBasicinfo(commonEmployee);
String otherinfo = "工作" + commonEmployee.getJob() + "\t";
return basicinfo + otherinfo;
}
}
继续书写抽象员工类
public abstract class Employee{
public final static int MALE = 0;
public final static int FEMALE = 1;
// 工资
private String name;
// 薪水
private int salary;
// 性别
private int sec;
// get/set
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getSalary(){
return salary;
}
public void setSalary(int salary){
this.salary = salary;
}
public int getSex(){
return sex;
}
public void setSex(int sex){
this.sex = sex;
}
// 定义访问者访问
public abstract void accept(IVisitor visitor);
}
普通员工
public class CommonEmployee extends Employee{
// 工作内容
private String job;
// 获得job
public String getJon(){
return job;
}
// 设置job
public void setJob(String job){
this.job = job;
}
// 允许访问者访问
@Override
public void accept(IVsitor visitor){
visitor.visit(this);
}
}
场景类
public class Client{
public static void main(String[] args){
// 开始循环列表
for(Employee emp:mockEmployee()){
// 将访问者传入,此时accept将会调用visit方法,将this传入
emp.accept(new Visitor());
}
}
public static List mockEmployee(){
List empList = new ArrayList();
// 产生员工
CommonEmployee zhangSan = new CommonEmployee();
// 设置属性
zhangSan.setJon("编写程序");
zhangSan.setName("张三");
zhangSan.setSalary(1800);
zhangSan.setSex(Employee.MALE);
empList.add(zhangSan);
// 产生员工
CommonEmployee liSi = new CommonEmployee();
liSi.setJob("美工");
liSi.setSalary("李四");
liSi.setSalary(1900);
liSi.setSex(Employee.FEMALE);
// 入数组
empList.add(liSi);
// 产生经理
Manager wangWu = new Manager();
wangWu.setName("王五");
wangWu.setPerformance("负数");
wangWu.setSalary(18750);
wangWu.setSex(Employee.MALE);
empList.add(wangWu);
return empList;
}
}
扩展
统计功能
汇总和报表,经常使用统计功能。
即,一堆计算公式,生产出一个报表。
统计公式员工的工资总额
// 定义抽象访问者
public interface IVisitor{
// 定义可以访问的普通员工
public void visit(CommonEmployee commonEmployee);
// 再次定义访问部门经理
public void visit(Manager manager);
// 统计员工工资总和
public int getTotalSalary();
}
定义访问者
// public class Visitor implements IVisitor{
// 这里实现接口
}
最后编写场景类
public class Client{
public static void main(String[] args){
// 定义一个访问者
// 展示报表的访问者
ISVisitor showVisitor = new Visitor();
// 汇总报表的访问者
ITotalVisitor totalVisitor = new TotalVisitor();
// 遍历,其中mockEmployee是从持久层传来的数据
for(Employee emp:mockEmployee()){
// 对数据进行处理,
// 代执行访问着的visit方法。由于数据是保存在emp的,所以需要将this传入
emp.accept(showVisitor);
emp.accept(totalVisitor);
}
System.out.println("");
}
}
双分派
单分派:处理一个操作根据请求着的名称和接受到的参数决定
静态绑定,动态绑定,依据重载,覆写实现。
栗子
// 定义角色接口,实现类
public interface Role{
// 演员扮演的角色
}
public class KungFuRole implements Role{
// 武功第一的角色
}
public class idiotRole implements Role{
// 弱智角色
}
下面定义抽象演员
public abstract class AbsActor{
// 演员能够扮演的角色
public void act(Role role){
// 演员扮演的角色
}
// 扮演功夫戏
public void act(KungFuRole role){
// 扮演功夫戏
}
}
// 青年演员,老年演员
public class YoungActor extends AbsActor{
// 年轻演员喜欢的功夫戏
public void act(KungFuRole role){
}
}
// 老年演员喜欢的功夫戏
public class OldActor extends AbsActor{
// 扮演功夫角色
public void act(KungFuRole role){
// 扮演功夫角色
}
}
编写场景
public class Client{
public static void main(String[] args){
// 定义一个演员
AbsActor actor = new OldActor();
// 定义一个角色
Role role = new KungFuRole();
// 开始演戏
actor.act(role);
actor.act(new KungFuRole());
}
}
重载在编译期间决定要调用那个方法。
静态绑定,是重写的时候就断定要绑定那个,例如定义年轻演员的时候,重写的act方法,此时为静态绑定了KungFuRole,
动态绑定呢,act方法,只有在运行的时候才能判断是和那个绑定
一个演员可以扮演多个角色,如何实现呢,使用访问者模式
public interface Role{
// 演员扮演的角色
public void accept(AbstActor actor);
}
public class KungFuRole implements Role{
// 角色
public void accept(Abstract actor){
actor.act(this);
}
}
public class ldiotRole implements Role{
// 弱智角色
public void accept(AbsActor actor){
actor.act(this);
}
}
书写场景类
public class Clicent{
public static void main(String[] args){
// 定义演员
AbsActor actor = new OldActor();
// 定义角色
Role role = new KungFuRole();
// 开始演戏
role.accept(actor);
}
}
总结
在上面的栗子中,角色只有在运行期间才能判断由那个演员执行,演员事先定义和那个角色绑定,所以角色使用接口,演员使用抽象类。
接口,抽象类 接口呢 是在运行的时候才能发现,所以使用动态绑定,抽象类适合使用静态绑定。啊哈,这就是接口和抽象类的区别。
访问者模式的核心在于定义一个方法,就像开启一个门,让访问者进入,然后在将其信息传递给访问者,由访问者执行需要产生的内容。
应用
过滤展示,报表,ui展示,过滤器,拦截器
在无知的道路上缓步前行