访问者模式

2019-01-24 03:24:43 浏览数 (2)

首先

抽象员工

代码语言:txt复制
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();
}

下面是普通员工

代码语言:txt复制
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";
    }
}

管理层

代码语言:txt复制
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";
    }
}

最后场景

代码语言:txt复制
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;
    }
}

改造如下

先定义访问者接口

代码语言:txt复制
public interface IVisitor{
    // 定义普通员工
    public void vsit(CommonEmployee commonEmployee);
    // 定义访问部门经理
    public void visit(Manager manager);
}

访问者实现

代码语言:txt复制
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;
    }
    
}

继续书写抽象员工类

代码语言:txt复制
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);
}

普通员工

代码语言:txt复制
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);
    }
}

场景类

代码语言:txt复制
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;
    }
}

扩展

统计功能

汇总和报表,经常使用统计功能。

即,一堆计算公式,生产出一个报表。

统计公式员工的工资总额

代码语言:txt复制
// 定义抽象访问者
public interface IVisitor{
    // 定义可以访问的普通员工
    public void visit(CommonEmployee commonEmployee);
    // 再次定义访问部门经理
    public void visit(Manager manager);
    // 统计员工工资总和
    public int getTotalSalary();
}

定义访问者

代码语言:txt复制
// public class Visitor implements IVisitor{
    // 这里实现接口
}

最后编写场景类

代码语言:txt复制
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("");
    }
}

双分派

单分派:处理一个操作根据请求着的名称和接受到的参数决定

静态绑定,动态绑定,依据重载,覆写实现。

栗子

代码语言:txt复制
// 定义角色接口,实现类
public interface Role{
    // 演员扮演的角色
}
public class KungFuRole implements Role{
    // 武功第一的角色
}
public class idiotRole implements Role{
    // 弱智角色
}

下面定义抽象演员

代码语言:txt复制
public abstract class AbsActor{
    // 演员能够扮演的角色
    public void act(Role role){
        // 演员扮演的角色
    }
    // 扮演功夫戏
    public void act(KungFuRole role){
        // 扮演功夫戏
    }
}
代码语言:txt复制
// 青年演员,老年演员
public class YoungActor extends AbsActor{
    // 年轻演员喜欢的功夫戏
    public void act(KungFuRole role){
    
    }
}
代码语言:txt复制
// 老年演员喜欢的功夫戏
public class OldActor extends AbsActor{
    // 扮演功夫角色
    public void act(KungFuRole role){
        // 扮演功夫角色
    }
}

编写场景

代码语言:txt复制
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方法,只有在运行的时候才能判断是和那个绑定

一个演员可以扮演多个角色,如何实现呢,使用访问者模式

代码语言:txt复制
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展示,过滤器,拦截器

qrcode_for_gh_9901b36b3b0e_258.jpgqrcode_for_gh_9901b36b3b0e_258.jpg

0 人点赞