设计模式之访问者模式
在讲解访问者模式之前,我们先来看一个例子:假设现阶段公司的技术部门要求员工汇总各自的基础信息,以及工作内容。
代码结构如下:
public class Visitor_01 {
//员工抽象类
abstract static class Employee{
private String name;//名字
private int salary;//薪水
private String job;//工作内容
public Employee(String name, int salary, String job) {
this.name = name;
this.salary = salary;
this.job = job;
}
public void report(){
String report = new StringBuilder()
.append("姓名:"+this.name)
.append(" 薪水:"+this.salary)
.append(" 工作:"+this.job)
.append(this.getOtherInfo())
.toString();
System.out.println(report);
}
public abstract String getOtherInfo();
}
//管理层
static class Leader extends Employee{
public Leader(String name, int salary, String job) {
super(name, salary, job);
}
@Override
public String getOtherInfo() {
return new StringBuilder().append(" 其他:爱拍马屁!!!").toString();
}
}
//普通员工
static class CommonEmploee extends Employee{
public CommonEmploee(String name, int salary, String job) {
super(name, salary, job);
}
@Override
public String getOtherInfo() {
return new StringBuilder().append(" 其他:技术研究!!!").toString();
}
}
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Leader("张三",18000, "管理员工"));
employees.add(new CommonEmploee("李四", 15000, "架构设计"));
employees.add(new CommonEmploee("王五", 12000, "写业务逻辑"));
for (Employee employee : employees) {
employee.report();
}
}
}
这是一个最基础的,使用了模板方法的一个设计。这里的report()是一个模板方法,定义了所有员工报告格式的大致框架,但是作为领导和普通员工的区别来讲,报告的格式和内容会有一些区别。如果领导类和普通员工类都遵循这个模板方法的话,一旦改方法结构变化,就会影响到所有的子类,这不是我们想要看到的。我们期望的设计是,员工和领导的报告细节的变更互不影响。
在这个实例里,普通员工类和领导类都是属于被大老板访问的对象,这个时候大老板就是一个访问者,只是他访问的对象不一样而已,有可能是领导,有可能是普通员工。那我们作为下级员工来讲,必须是允许领导来访问的;但是大老板访问下级员工到底想要知道些什么呢,这就应该由大老板自己来决定才行,因为下属信息对大老板都是透明的。
下面修改下设计:
public class Visitor_02 {
interface IVisitor{
void visitor(Leader leader);
void visitor(CommonEmploee commonEmploee);
}
static class Visitor implements IVisitor{
@Override
public void visitor(Leader leader) {
String report = new StringBuilder()
.append("姓名:"+leader.getName())
.append(" 薪水:"+leader.getSalary())
.append(" 工作:"+leader.getJob())
.append(" 其他:爱拍马屁")
.toString();
System.out.println(report);
}
@Override
public void visitor(CommonEmploee commonEmploee) {
String report = new StringBuilder()
.append("姓名:"+commonEmploee.getName())
.append(" 薪水:"+commonEmploee.getSalary())
.append(" 工作:"+commonEmploee.getJob())
.append(" 其他:技术研究")
.toString();
System.out.println(report);
}
}
//员工抽象类
abstract static class Employee{
private String name;//名字
private int salary;//薪水
private String job;//工作内容
public Employee(String name, int salary, String job) {
this.name = name;
this.salary = salary;
this.job = job;
}
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 String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public abstract void accept(IVisitor iVisitor);
}
//管理层
static class Leader extends Employee{
public Leader(String name, int salary, String job) {
super(name, salary, job);
}
@Override
public void accept(IVisitor iVisitor) {
iVisitor.visitor(this);
}
}
//普通员工
static class CommonEmploee extends Employee{
public CommonEmploee(String name, int salary, String job) {
super(name, salary, job);
}
@Override
public void accept(IVisitor iVisitor) {
iVisitor.visitor(this);
}
}
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Leader("张三",18000, "管理员工"));
employees.add(new CommonEmploee("李四", 15000, "架构设计"));
employees.add(new CommonEmploee("王五", 12000, "写业务逻辑"));
Visitor visitor = new Visitor();
for (Employee employee : employees) {
employee.accept(visitor);
}
}
}
如上代码:
- 定义一个访问者接口,定义访问不同具体对象的方法;
- 定义一个抽象的类,提供一个接收访问者的抽象方法,由子类实现;
- 定义一个具体的访问者实现类,来访问具体的被访问者,并进行逻辑处理;
- 具体的被访问对象的像访问者暴露自己的所有信息。
以上就是访问者模式的基本设计代码以及思路,下面看看官方的访问者模式的定义:封装一些作用于某种数据结构中的各个元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新操作。
简单来讲,就是暴露自己信息或结构给访问者,让访问者自己来实现逻辑。这样逻辑的变更不会影响到自己内部的结构。
但是由于visitor方法接收到的都是具体的类实例,并不是面向接口编程,所以扩展性不好。
参考编译器:ASM动态生成字节码