访问者模式

将数据操作和数据结构分离的设计模式-访问者模式

定义

封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作

使用场景

  1. 对象结构比较稳定,但经常需要在此对象结构上定义新的操作
  2. 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免这些操作“污染这些对象的类,也不希望再增加新操作时修改这些类

简单实现

员工基类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package VisitorMode;

import java.util.Random;

public abstract class Staff {
    public String name;
    public int kpi;

    public Staff(String name) {
        this.name = name;
        kpi=new Random().nextInt(10);
    }
    public abstract void accept(Visitor visitor);
}

工程师

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package VisitorMode;


import java.util.Random;

public class Engineer extends Staff {
    public Engineer(String name) {
        super(name);
    }

    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public int getCodeLines(){
        return new Random().nextInt(10*10000);
    }


}

经理类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package VisitorMode;

import java.util.Random;

public class Manager extends Staff {
    private int products;

    public Manager(String name) {
        super(name);
        products=new Random().nextInt(10);
    }

    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public int getProducts(){
        return products;
    }
}

Visitor类型

1
2
3
4
5
6
7
package VisitorMode;


public interface Visitor {
    public void visit(Engineer engineer);
    public void visit(Manager manager);
}

Visitor接口 CEO

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package VisitorMode;

public class CEOVisitor implements Visitor {
    public void visit(Engineer engineer) {
        System.out.println("工程师"+engineer.name+"kpi:"+ engineer.kpi);
    }

    public void visit(Manager manager) {
        System.out.println("经理"+manager.name+"kpi:"+manager.kpi+"新产品数量:"+manager.getProducts());
    }
}

Visitor类型 CTO

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package VisitorMode;

public class CTOVisitor implements Visitor {
    public void visit(Engineer engineer) {
        System.out.println("工程师"+engineer.name+"代码数量"+engineer.getCodeLines());
    }

    public void visit(Manager manager) {
        System.out.println("经理:"+manager.name+"产品数量:"+manager.getProducts());
    }
}

员工业务报表1类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package VisitorMode;

import java.util.LinkedList;
import java.util.List;

public class BusinessReport {
    List<Staff> mStaffs=new LinkedList<Staff>();

    public BusinessReport(){
        mStaffs.add(new Manager("王经理"));
        mStaffs.add(new Engineer("工程师1-shaw"));
        mStaffs.add(new Engineer("工程师2-shaw"));
        mStaffs.add(new Engineer("工程师3-shaw"));
        mStaffs.add(new Engineer("工程师4-shaw"));
    }

    //为访问者添加报表
    public void showReport(Visitor visitor){
        for (Staff staff:mStaffs){
            staff.accept(visitor);
        }
    }
}

测试代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package VisitorMode;

public class Client {
    public static void main(String[] args) {
        BusinessReport businessReport=new BusinessReport();
        System.out.println("=========CEO报表===============");
        businessReport.showReport(new CEOVisitor());
        System.out.println("=========CTO报表===============");
        businessReport.showReport(new CTOVisitor());
    }
}

执行结果:

result.png

总结

优点

  1. 各角色职责分离,符合单一职责原则
  2. 具有优秀的拓展性
  3. 使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化
  4. 灵活性

缺点

  1. 具体元素对访问者公布细节,违反了迪米特原则
  2. 具体元素变更时导致修改成本大
  3. 违反了依赖倒置原则,为了到达“区别对待”而依赖了具体类,没有依赖抽象