设计模式(十八)—访问者模式
最后更新于: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();
}
}
~~~
**访问者模式的优点:**
符合单一职责原则
优秀的扩展性
灵活性非常高
**访问者模式的缺点:**
具体元素对访问者公布细节
具体元素变更比较困难
违背了依赖倒置原则