无环访问者模式(Acyclic Visitor Pattern)
文章目录
前提概要
⭐️本文章阅读的前提,是已经理解使用的访问者模式及相关概念,如若未了解过/未使用过,可参考我之前的文章
访问者模式
:https://blog.csdn.net/zhangHP_123/article/details/126352689?spm=1001.2014.3001.5501
一. 概念
基于访问者模式,不会创建GoF访问者模式固有的麻烦依赖循环,并允许向现有类的层次等级结构中添加函数,而不会影响这些层次结构
二. 解决的问题
- 基于访问者模式,解决了强耦合的2个继承体系的循环依赖
- 被访问者继承层次修改了,也不需要修改访问者层次,只需要扩展一下即可,而且访问者可以自由组合较之以前更为灵活方便。
- 增加了权限等级层次
三. 使用场合
- 在访问者使用场合的基础上,并打破循环依赖体系的访问者模式,可随意添加权限层次等级的访问者
- 在无需改变影响的情况下,对于已存在的等级结构,添加所需要的功能
- 根据不同的对象类型,添加不同的操作
- 当访问类
层次结构
经常被扩展,并为新元素类所用 - 基于固有的访问者模式的循环依赖,重新分配,编译,连接成本特别昂贵时
- 当操作的访问者层次结构,不属于该层次结构时(如下面的示例代码中的ConfigureLeaderVisitor,ConfigureEmployeeVisitor,ConfigureAccountantVisitor)
四. 优点及缺点
- 优点
- 对于类等级体系,没有固有的依赖循环结构
- 添加一个新的访问者,无需修改所有的访问者
- 由于脱离了依赖循环,即使添加一个新的访问之编译出错,也不会影响已存在的访问者
- 缺点
- 违反里斯科夫替代原则,表明它可以接受所有访客,但实际上只对特定访客感兴趣。
- 必须为可访问类层次结构中的所有成员创建并行访问器层次结构。
五. 无环访问者模式结构图
六. 小试牛刀
6.1 例子
在一个公司里,有领导,会计,员工等等不同的职位
对于领导的话,员工,会计这样的职位等级,由于领导平常里都很忙,他们是没有权限访问见面的
对于员工,会计的话,是可以相互访问见面的
那么对于这两种情况,如何实现的,如果以后公司规模变大,会有更多职位等级的出现及访问权限,又如何实现呢
对于这些情况,无环访问者很巧妙的解决了
6.2 UML
通过不同的接口实现,来达到上述问题的效果
6.3 代码实现
⭐️依赖
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.7.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
⭐️Company - 公司
/**
* 公司
*
* @author zhanghp
* @date 2022-08-16 15:07
*/
public interface Company {
void accept(CompanyVisitor visitor);
}
⭐️Leader - 领导
/**
* 领导
*
* @author zhanghp
* @date 2022-08-16 15:07
*/
@Slf4j
public class Leader implements Company{
@Override
public void accept(CompanyVisitor visitor) {
if (visitor instanceof LeaderVisitor) {
((LeaderVisitor) visitor).visit(this);
}else {
log.warn("Only LeaderVisitor is allowed to visit the Leader, your visitor identity is {}", visitor);
}
}
@Override
public String toString() {
return " --> Leader <-- ";
}
}
⭐️Employee - 员工
/**
* 员工
*
* @author zhanghp
* @date 2022-08-16 15:07
*/
@Slf4j
public class Employee implements Company{
@Override
public void accept(CompanyVisitor visitor) {
if (visitor instanceof EmployeeVisitor) {
((EmployeeVisitor) visitor).visit(this);
}else {
log.warn("Only EmployeeVisitor is allowed to visit the Employee / Accountant, your visitor identity is {}", visitor);
}
}
@Override
public String toString() {
return " --> Employee <-- ";
}
}
⭐️Accountant - 会计
/**
* 会计
*
* @author zhanghp
* @date 2022-08-16 15:08
*/
@Slf4j
public class Accountant implements Company{
@Override
public void accept(CompanyVisitor visitor) {
if (visitor instanceof AccountantVisitor) {
((AccountantVisitor) visitor).visit(this);
}else {
log.warn("Only AccountantVisitor is allowed to visit the Accountant / Employee, your visitor identity is {}", visitor);
}
}
@Override
public String toString() {
return " --> Accoutant <-- ";
}
}
⭐️CompanyVisitor - 总访问者
/**
* 总访问者
*
* @author zhanghp
* @date 2022-08-16 15:10
*/
public interface CompanyVisitor {
}
⭐️LeaderVisitor - 领导访问者接口
/**
* 领导访问者接口
*
* @author zhanghp
* @date 2022-08-16 15:10
*/
public interface LeaderVisitor extends CompanyVisitor {
void visit(Leader leader);
}
⭐️EmployeeVisitor - 员工访问者接口
/**
* 员工访问者接口
*
* @author zhanghp
* @date 2022-08-16 15:11
*/
public interface EmployeeVisitor extends CompanyVisitor{
void visit(Employee employee);
}
⭐️AccountantVisitor - 会计访问者接口
/**
* 会计访问者接口
*
* @author zhanghp
* @date 2022-08-16 15:11
*/
public interface AccountantVisitor extends CompanyVisitor{
void visit(Accountant accountant);
}
⭐️AllCompanyVisitor - 总访问者
/**
* AllCompanyVisitor 继承所有的访问接口,访问者可以访问所有的类型
*
* @author zhanghp
* @date 2022-08-16 15:11
*/
public interface AllCompanyVisitor extends AccountantVisitor, EmployeeVisitor, LeaderVisitor{
}
⭐️PartCompanyVisitor - 部分访问者
/**
* 用于部分访问者相互访问
*
* @author zhanghp
* @date 2022-08-25 17:29
*/
public interface PartCompanyVisitor extends AccountantVisitor, EmployeeVisitor{
}
⭐️ConfigureLeaderVisitor - 领导访问实现类
/**
* 领导访问实现类
*
* @author zhanghp
* @date 2022-08-16 15:12
*/
@Slf4j
public class ConfigureLeaderVisitor implements AllCompanyVisitor {
@Override
public void visit(Accountant accountant) {
log.info("node to {}", accountant);
}
@Override
public void visit(Employee employee) {
log.info("node to {}", employee);
}
@Override
public void visit(Leader leader) {
log.info("I am your {}", leader);
}
@Override
public String toString() {
return " -->Leader<-- ";
}
}
⭐️ConfigureEmployeeVisitor - 员工访问实现类
/**
* 员工访问实现类
*
* @author zhanghp
* @date 2022-08-16 15:12
*/
@Slf4j
public class ConfigureEmployeeVisitor implements PartCompanyVisitor {
@Override
public void visit(Employee employee) {
log.info("Hello {}", employee);
}
@Override
public void visit(Accountant accountant) {
log.info("Hello {}", accountant);
}
@Override
public String toString() {
return " -->Employee<-- ";
}
}
⭐️ConfigureAccoutantVisitor - 会计访问者实现类
/**
* 会计访问者实现类
*
* @author zhanghp
* @date 2022-08-16 15:12
*/
@Slf4j
public class ConfigureAccountantVisitor implements PartCompanyVisitor {
@Override
public void visit(Accountant accountant) {
log.info("Hi {}", accountant);
}
@Override
public void visit(Employee employee) {
log.info("Hi {}", employee);
}
@Override
public String toString() {
return " -->Accountant<-- ";
}
}
七. UT测试用例
7.1 代码
@Slf4j
public class App {
public static void main(String[] args) {
// 访问者
var conLeader = new ConfigureLeaderVisitor();
var conEmployee = new ConfigureEmployeeVisitor();
var conAccoutant = new ConfigureAccountantVisitor();
// 元素
var leader = new Leader();
var employee = new Employee();
var accountant = new Accountant();
// 访问
log.info("leader visitor start");
leader.accept(conLeader);
employee.accept(conLeader);
accountant.accept(conLeader);
log.info("employee visitor start");
leader.accept(conEmployee);
employee.accept(conEmployee);
accountant.accept(conEmployee);
log.info("accountant visitor start");
leader.accept(conAccoutant);
employee.accept(conAccoutant);
accountant.accept(conAccoutant);
}
}
public class AcyclicTest {
@Test
void testEmployee() {
// 成员准备
Leader leader = new Leader();
Employee employee = new Employee();
Accountant accountant = new Accountant();
// 各个成员访问Employee
leader.accept(new ConfigureEmployeeVisitor());
employee.accept(new ConfigureEmployeeVisitor());
accountant.accept(new ConfigureEmployeeVisitor());
}
@Test
void testAccountant() {
// 成员准备
Leader leader = new Leader();
Employee employee = new Employee();
Accountant accountant = new Accountant();
// 各个成员访问Accountant
leader.accept(new ConfigureAccountantVisitor());
employee.accept(new ConfigureAccountantVisitor());
accountant.accept(new ConfigureAccountantVisitor());
}
@Test
void testLeader() {
// 成员准备
Leader leader = new Leader();
Employee employee = new Employee();
Accountant accountant = new Accountant();
// 各个成员访问Leader
leader.accept(new ConfigureLeaderVisitor());
employee.accept(new ConfigureLeaderVisitor());
accountant.accept(new ConfigureLeaderVisitor());
}
@Test
void all() {
assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
7.2 打印结果
1. testEmployee:
- Only LeaderVisitor is allowed to visit the Leader, your visitor identity is -->Employee<--
- Hello --> Employee <--
- Hello --> Accoutant <--
2. testAccountant:
- Only LeaderVisitor is allowed to visit the Leader, your visitor identity is -->Accountant<--
- Hi --> Employee <--
- Hi --> Accoutant <--
3. testLeader:
- I am your --> Leader <--
- node to --> Employee <--
- node to --> Accoutant <--
4. all:
- leader visitor start
- I am your --> Leader <--
- node to --> Employee <--
- node to --> Accoutant <--
- employee visitor start
- Only LeaderVisitor is allowed to visit the Leader, your visitor identity is -->Employee<--
- Hello --> Employee <--
- Hello --> Accoutant <--
- accountant visitor start
- Only LeaderVisitor is allowed to visit the Leader, your visitor identity is -->Accountant<--
- Hi --> Employee <--
- Hi --> Accoutant <--
八. 参考资料及源码地址
iluwater:https://github.com/iluwatar/java-design-patterns/blob/master/acyclic-visitor/README.md
📌源码:https://gitee.com/zhp1221/design_pattern/tree/master/lab_03_acyclic_visitor