首先

抽象员工

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展示,过滤器,拦截器

qrcode_for_gh_9901b36b3b0e_258-1