这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战
欢迎来到今天的学习,今天我们一起来学习下访问者代理模式。多唠叨几句,本月将会对java的设计模式精讲,欢迎点击头像,关注我的专栏,我会持续更新,加油!
系列文章:
...持续更新中
话不多说,进入正题
访问者模式
个人认为该模式在实际开发中运用并不是很多,但是一旦要用到了,那便是无可替代的。
访问者模式的原始定义是:访问者模式是一种将数据操作和数据结构分离的设计模式。允许在运行时将一个或多个操作应用于一组对象,将操作与对象结构分离。
访问者模式核心关注点是分离一组对象结构和对象的操作,对象结构可以各不相同,但必须以某一个或一组操作作为连接的中心点。换句话说,访问者模式是以行为(某一个操作)作为扩展对象功能的出发点,在不改变已有类的功能的前提下进行批量扩展。
听起来是不是很抽象,当然这是很官方,很专业的词来解释,这理解起来可能费点劲,但是我今天会用最通俗的的场景和代码来帮助你理解和学习。(当你看完我下面的例子讲解之后,你回来再看这段话,便想说SO DE SI NE)
下面来看张图(图片来源于网络)
针对上图我们做一下介绍:
-
Visitor:接口或者抽象类,定义了访问者类型访问的类型和行为,它的参数就是被访问的元素,它的方法个数理论上与元素的个数是一样的,因此,访问者模式要求元素的类型要稳定,如果经常添加、移除元素类,必然会导致频繁地修改 Visitor 接口,如果出现这种情况,则说明不适合使用访问者模式。 注意这里,如果经常添加、移除元素类,必然会导致频繁地修改 Visitor 接口,如果出现这种情况,则说明不适合使用访问者模式,那样便违背了迪米特法则与开放原则。
-
Element:元素接口或者抽象类,它定义了一个接受访问者(accept)的方法,其意义是指每一个元素都要可以被访问者访问。
注意这里,这里可以代指访问者的入口,可以理解成访问者,从这个方法内去分别访问不同的对象,不同的元素
- ElementA、ElementB:具体的元素类,它提供接受访问的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。
注意这里,说通俗点,就是接口的实现类,此元素被访问到完全是根据调用者的参数来决定
- ObjectStructure 定义当中所提到的对象结构,对象结构是一个抽象表述,它内部管理了元素集合,并且可以迭代这些元素提供访问者访问。
注意这里,我们知道,实际工作当中,可能会有若干个元素类,那么ObjectStructure便是管理这些元素类的。
如果你看到这里还是依然觉得很抽象,便看下面的代码示例!
代码示例
我们想象这样一种场景,面试官(CTO)和研发人员(技术总监面试技术开发),当然还有我们的产品经理面试产品助理。研发人员对于CTO而言,CTO主要在意面试者的技术经验,而产品经理(CPO)在意产品助理的产品的经验
那么问题来了,这两者的关注点是不一样的。这就需要技术总监和产品经理(CPO)两种职位进行不同的处理。访问者模式此时可以派上用场了。
//面试者
public abstract class Interviewers {
//面试者姓名
public String name;
public int experience ;// 面试者经验(暂时用工作年限作为直接经验)
public Interviewers(String name) {
this.name = name;
experience = new Random().nextInt(10);
}
// 核心方法,接受Visitor的访问
public abstract void accept(Visitor visitor);
}
Interviewers 类定义了面试者基本信息及一个 accept 方法,accept 方法表示接受访问者的访问,由子类具体实现。Visitor 是个接口,传入不同的实现类,可访问不同的数据。下面看看技术开发工程师和产品助理的代码:
// 工程师
public class Engineer extends Interviewers {
public Engineer(String name) {
super(name);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
// 工程师经验值(为代码量)
public int getCodeLines() {
return new Random().nextInt(10 * 10000);
}
}
//产品助理
public class Product extends Interviewers {
public Product(String name) {
super(name);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
// 产品助理产品数量
public int getProducts() {
return new Random().nextInt(10);
}
}
工程师是代码数量,产品助理是产品数量,他们的职责不一样,也就是因为差异性,才使得访问模式能够发挥它的作用。Interviewers、Engineer、Product 3个类型就是对象结构,这些类型相对稳定,不会发生变化。
下面看看 Visitor 类型的定义, Visitor 声明了两个 visit 方法,分别是对工程师和经理对访问函数,具体代码如下:
public interface Visitor {
// 访问工程师类型
void visit(Engineer engineer);
// 产品助理类型
void visit(Product product);
}
首先定义了一个 Visitor 接口,该接口有两个 visit 函数,参数分别是 Engineer、Product,也就是说对于 Engineer、Product 的访问会调用两个不同的方法,以此达成区别对待、差异化处理。具体实现类为 CTOVisitor、CPOVisitor类,具体代码如下:
// CTO访问者
public class CTOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
System.out.println("开发工程师: " + engineer.name + ", 年限和代码量: " + engineer.getProducts);
}
@Override
public void visit(Product product) {
System.out.println("产品助理: " + product.name + ", KPI: " + manager.kpi +
", 新产品数量: " + product.getProducts());
}
}
OK,到这里就结束