一、访问者模式(行为型模式)
1.定义
访问者模式(Vistor Pattern)是一种将数据结构和数据操作分离的设计模式。是指封装一些作用于某种数据结构中的各种元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新操作。
2.访问者模式解释
访问者模式的基本思想使针对系统中拥有的某些固定类型的对象结构(元素),在其内部提供一个accept()方法用来接受访问者对象的访问。不同的访问者对同一元素的访问内容不同,所以使得相同的元素可以产生不同的元素结果。就是说不同的访问者访问同一个对象里面的不同属性,产生了不同的结果。
3.访问者模式角色
**(1).抽象访问者(Vistor):**这个角色主要是定义对具体元素的访问方法,参数就是具体元素,理论上来说方法数等于元素(固定类型的对象,也就是被访问者)个数。
**(2).具体访问者(ConcreteVistor):**实现对具体元素的访问。
**(3).抽象元素(Element):**定义一个接受访问访问的方法。
**(4).具体元素(Concrete Element):**提供接受访问者访问的具体实现。
**(5).结构对象(Object Struture):**用来维护元素,并提供一个方法来接受访问者访问所有的元素。
4.代码实现方式
(1).创建一个抽象元素接口,定义一个accept(Vistor vistor)方法,用来接受访问者,入参是访问者对象。
(2).创建一个具体元素类,实现抽象元素接口,重写accept(Vistor vistor)方法,方法内部调用访问者的visit()方法。
(3).创建一抽象访问者接口,定义一个visit()方法。
(4).创建一个具体访问者类,实现抽象访问者接口,实现visit()方法。
(5).创建一个结构对象类,维护一份具体元素集合,提供一个添加元素和一个访问全部具体元素的方法。
5.代码实现
(1).场景
比如公司年终总结,公司CEO、CTO想看下全年项目情况,这里员工分为普通员工和项目经理,CEO在乎的是员工的kpi和项目数,而CEO关心的是员工kpi和完成项目数,而CTO关心的是员工代码量和完成项目数。(这不就不同的访问者对同一个固定元素的访问内容不同,产生不同的结果)
(2).具体代码
package com.tw.designPattern.visitor.demo;
/**
* 员工 抽象元素 被访问者
*/
public interface Employee {
void accept(Visitor visitor);
}
package com.tw.designPattern.visitor.demo;
import java.util.Random;
/**
* 工程师 具体元素 被访问者
*/
public class Engineer implements Employee {
private String name;
private int kpi;
Engineer(String name){
this.name = name;
this.kpi = new Random().nextInt(10);
}
public String getName() {
return name;
}
public int getKpi() {
return kpi;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public int getCodeLineTotal(){
return this.kpi * 1000000;
}
}
package com.tw.designPattern.visitor.demo;
import java.util.Random;
/**
* 管理者 具体元素 被访问者
*/
public class Manager implements Employee{
private String name;
private int kpi;
Manager(String name){
this.name = name;
this.kpi = new Random().nextInt(10);
}
public String getName() {
return name;
}
public int getKpi() {
return kpi;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public int getProductNum(){
return this.kpi * 10;
}
}
package com.tw.designPattern.visitor.demo;
/**
* 访问者 抽象访问者
*/
public interface Visitor {
void visit(Engineer engineer);
void visit(Manager manager);
}
package com.tw.designPattern.visitor.demo;
/**
* CEO 具体访问者
*/
public class CEOVisitor implements Visitor{
@Override
public void visit(Engineer engineer) {
System.out.println("工程师:" + engineer.getName() + "KPI:" + engineer.getKpi());
}
@Override
public void visit(Manager manager) {
System.out.println("经理:" + manager.getName() + "KPI:" + manager.getKpi() + " 今年共完成项目:" + manager.getProductNum() + "个");
}
}
package com.tw.designPattern.visitor.demo;
/**
* CTO 具体访问者
*/
public class CTOVisitor implements Visitor{
@Override
public void visit(Engineer engineer) {
System.out.println("工程师:" + engineer.getName() + " 今年代码量" + engineer.getCodeLineTotal() + "行");
}
@Override
public void visit(Manager manager) {
System.out.println("经理:" + manager.getName() + " 今年共完成项目:" + manager.getProductNum() + "个");
}
}
package com.tw.designPattern.visitor.demo;
import java.util.ArrayList;
import java.util.List;
/**
* 结构对象
*/
public class EmployeeStructure {
List<Employee> list = new ArrayList<>();
public EmployeeStructure addEmployee(Employee employee){
list.add(employee);
return this;
}
public void report(Visitor visitor){
list.forEach(employee -> {
employee.accept(visitor);
});
}
}
package com.tw.designPattern.visitor.demo;
public class EmployeeTest {
public static void main(String[] args) {
Engineer engineerZ = new Engineer("小张");
Engineer engineerW = new Engineer("小王");
Engineer engineerL = new Engineer("小李");
Manager managerZ = new Manager("张总");
Manager managerW = new Manager("王总");
Manager managerL = new Manager("李总");
EmployeeStructure structure = new EmployeeStructure();
structure.addEmployee(engineerZ).addEmployee(engineerW).addEmployee(engineerL).addEmployee(managerZ).addEmployee(managerW).addEmployee(managerL);
structure.report(new CTOVisitor());
System.out.println("---------------------------------------");
structure.report(new CEOVisitor());
}
}
测试结果
工程师:小张 今年代码量0行
工程师:小王 今年代码量3000000行
工程师:小李 今年代码量9000000行
经理:张总 今年共完成项目:10个
经理:王总 今年共完成项目:20个
经理:李总 今年共完成项目:10个
---------------------------------------
工程师:小张KPI:0
工程师:小王KPI:3
工程师:小李KPI:9
经理:张总KPI:1 今年共完成项目:10个
经理:王总KPI:2 今年共完成项目:20个
经理:李总KPI:1 今年共完成项目:10个
6.优缺点
(1).优点
(1-1).解耦了数据结构和数据操作,使得操作集合可以独立变化。
(1-2).访问者角色非常容易扩展。
(1-3).每种角色各司其职,符合单一职责。
(2).缺点
(2-1).增加元素(被访问者)类型困难,如果改变了元素,需要修改访问者代码,违反开闭原则。
(2-2).违反了依赖倒置原则,比如访问者中入参依赖的是具体元素,而不是抽象元素。
7.应用场景
(1).数据结构稳定,但是作用域数据结构上的操作经常变化,比如像上面的访问者再来个某某管理者想看员工别的啥内容了。
(2).需要对不同数据类型进行操作,而不是用分支判断具体类型的场景。
注:内容参考网络上各种资料,还有一些本人的理解和思想,仅为了学习记录和分享一下自己所学之处,如有不足的地方麻烦大牛指出,如有侵权的地方,请联系删除,谢谢