设计模式(十八)—访问者模式

最后更新于:2022-04-01 16:26:34

**定义**:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。 ## 一般模式 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-06_5755340cd64ca.jpg) Visitor----抽象访问者 --|抽象类或接口,声明访问者可以访问那些元素,具体到程序中的就是visit的参数定义那些对象是可以被访问的。 ConcreteVisotor---抽象元素 ---|他影响访问者访问到类后,该怎么做,要做什么事情。 Element---抽象元素 --|接口或者抽象类,声明接受哪一类访问者访问,程序上通过accept方法中的参数定义 ConcreteElement---具体元素 --|实现accept方法,通常是visitor.visit(this),基本上都形成了一种模式了。 ObjectStruture---结构对象 --|元素产生者,一般容纳在多个不同类、不同接口的容器,如List、Set、Map等,在项目中,一般很少抽象出这个角色。 ~~~ public class VisitorTest { public static void main(String[] args) { //产生10个具体元素对象 for(int i=0;i<10;i++){ Element e = ObjectStruture.createElement(); //接收访问者访问 e.accept(new ConcreteVisitor()); } } } /** * 抽象元素类 * 除了有自己的业务逻辑外, * 定义哪一类的访问者,可以访问。 * @author admin * */ abstract class Element{ //执行自身的业务逻辑 public abstract void doSomenthing(); //定义访问者都有哪些 public abstract void accept(IVisitor visitor); } /** * 具体的实现元素类。 * 1、实现自身的具体业务逻辑 * 2、设置哪个访问者可以访问 * @author admin * */ class ConcreteElement1 extends Element{ @Override public void doSomenthing() { System.out.println("我是元素1的具体实现者..."); } @Override public void accept(IVisitor visitor) { visitor.visit(this); } } /** * 具体的实现元素类。 * 1、实现自身的具体业务逻辑 * 2、设置哪个访问者可以访问 * @author admin * */ class ConcreteElement2 extends Element{ @Override public void doSomenthing() { System.out.println("我是元素2的具体实现者..."); } @Override public void accept(IVisitor visitor) { visitor.visit(this); } } /** * 抽象访问者, * 声明访问者可以访问哪些类。具体的执行方法有子类去实现 * @author admin * */ interface IVisitor{ //定义访问ConcreteElement1类的具体实现 public void visit(ConcreteElement1 con1); //定义访问ConcreteElement2类的具体实现 public void visit(ConcreteElement2 con2); } /** * 访问者的具体实现类, * 访问者访问到类以后,做什么事情,有该类来具体实现 * @author admin * */ class ConcreteVisitor implements IVisitor{ @Override public void visit(ConcreteElement1 con1) { con1.doSomenthing(); System.out.println("----访问者1号,执行任务"); } @Override public void visit(ConcreteElement2 con2) { con2.doSomenthing(); System.out.println("----访问者2号,执行任务"); } } /** * 元素的产生者,用于产生被访问者类型的对象。 * @author admin * */ class ObjectStruture{ //利用一个随机数,产生实现类1和2的对象 public static Element createElement(){ Random random = new Random(); if(random.nextInt(100)>50){ return new ConcreteElement1(); } return new ConcreteElement2(); } } ~~~ ## 一个例子 一个公司有普通员工和经理,他们都有:姓名、性别、薪水。 私有属性:员工:job(工作),经理:performance(业绩)。 这里需要打印一堆报表,要求员工和经理的相互区分。如何设计合理呢? ~~~ public class VisitorT { public static void main(String[] args) { //打印公司员工的报表 for(Emploee e : mockEmploy()){ e.accept(new EmployeeVisitor()); } } //模拟公司所有的人员。 public static List<Emploee> mockEmploy(){ List<Emploee> employeeList = new ArrayList<Emploee>(); //创建一些普通员工 Employer common1 = new Employer(); common1.setName("lz"); common1.setJob("APP应用上市.."); common1.setSalary(12000); common1.setSex(1); Employer common2 = new Employer(); common2.setName("ly"); common2.setJob("APP应用上市.."); common2.setSalary(11000); common2.setSex(1); Employer common3 = new Employer(); common3.setName("ht"); common3.setJob("美工做好.."); common3.setSalary(10000); common3.setSex(2); //定义一个经理 Manager m = new Manager(); m.setName("lzl"); m.setPerformence("今天晚上一定加班..."); m.setSalary(1000000); m.setSex(1); //添加 employeeList.add(common3); employeeList.add(common1); employeeList.add(common2); employeeList.add(m); return employeeList; } } /** * 抽象的员工报表类, * 定义共有的属性方法。 * 并提供一个观察者类的接口 * @author admin * */ abstract class Emploee{ private String name; private int sex; private double salary; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public abstract void accept(IEmployeeVisitor visitor); } /** * 经理类的具体实现类。 * @author admin * */ class Manager extends Emploee{ //经理关注的是公司业绩 private String performence; public String getPerformence() { return performence; } public void setPerformence(String performence) { this.performence = performence; } @Override public void accept(IEmployeeVisitor visitor) { visitor.visit(this); } } /** * 普通员工的具体实现类。 * @author admin */ class Employer extends Emploee{ //普工关注的是工作 private String job; public String getJob() { return job; } public void setJob(String job) { this.job = job; } @Override public void accept(IEmployeeVisitor visitor) { visitor.visit(this); } } /** * 报表观察者接口类, * 设置观察者观察具体的实现类。 * 具体的实现方法,由实现类来完成 * @author admin * */ interface IEmployeeVisitor{ //设置观察普通员工 public void visit(Employer employer); //设置观察经理 public void visit(Manager manager); } /** * 具体的观察者实现类, * 实现类中观察到被观察者,之后需要打印报表。 * @author admin * */ class EmployeeVisitor implements IEmployeeVisitor{ @Override public void visit(Employer employer) { System.out.println(this.getEmployerInfo(employer)); } @Override public void visit(Manager manager) { System.out.println(this.getManageInfo(manager)); } //获取员工的基本共有信息 private String getBaseInfo(Emploee e){ String info = "姓名:"+e.getName()+"\t性别:"+ (e.getSex()==1 ? "男" : "女")+"\t薪水:"+e.getSalary(); return info; } //获取经理的所有信息 private String getManageInfo(Manager m){ String info = m.getPerformence(); return info+"\t"+getBaseInfo(m); } //获取普通员工的全部信息 private String getEmployerInfo(Employer e){ String info = e.getJob(); return info+"\t"+getBaseInfo(e); } } ~~~ 访问者模式的扩展 ---|统计功能 ~~~ interface IEmployeeVisitor{ //设置观察普通员工 public void visit(Employer employer); //设置观察经理 public void visit(Manager manager); //统计薪水功能 public void totalSalary(); } /** * 具体的观察者实现类, * 实现类中观察到被观察者,之后需要打印报表。 * @author admin * */ class EmployeeVisitor implements IEmployeeVisitor{ //经理总共薪资 private double totalManager=0; //普通员工薪资 private double totalEmployer=0; @Override public void visit(Employer employer) { this.getEmployer(employer); } @Override public void visit(Manager manager) { this.getManagerSalary(manager); } //统计总共的薪水 @Override public void totalSalary() { System.out.println( "公司一年支付的薪水是:"+this.totalEmployer + this.totalManager); } //统计经理的薪水 private void getManagerSalary(Manager m){ this.totalManager = this.totalManager + m.getSalary(); } //统计员工的薪水 private void getEmployer(Employer e){ this.totalEmployer = this.totalEmployer + e.getSalary(); } } ~~~ **访问者模式的优点:** 符合单一职责原则 优秀的扩展性 灵活性非常高 **访问者模式的缺点:** 具体元素对访问者公布细节 具体元素变更比较困难 违背了依赖倒置原则
';