设计模式 - 无环访问者模式

无环访问者模式(Acyclic Visitor Pattern)

前提概要

⭐️本文章阅读的前提,是已经理解使用的访问者模式及相关概念,如若未了解过/未使用过,可参考我之前的文章

访问者模式https://blog.csdn.net/zhangHP_123/article/details/126352689?spm=1001.2014.3001.5501

一. 概念

基于访问者模式,不会创建GoF访问者模式固有的麻烦依赖循环,并允许向现有类的层次等级结构中添加函数,而不会影响这些层次结构

二. 解决的问题

  1. 基于访问者模式,解决了强耦合的2个继承体系的循环依赖
  2. 被访问者继承层次修改了,也不需要修改访问者层次,只需要扩展一下即可,而且访问者可以自由组合较之以前更为灵活方便。
  3. 增加了权限等级层次

三. 使用场合

  1. 在访问者使用场合的基础上,并打破循环依赖体系的访问者模式,可随意添加权限层次等级的访问者
  2. 在无需改变影响的情况下,对于已存在的等级结构,添加所需要的功能
  3. 根据不同的对象类型,添加不同的操作
  4. 当访问类层次结构经常被扩展,并为新元素类所用
  5. 基于固有的访问者模式的循环依赖,重新分配,编译,连接成本特别昂贵时
  6. 当操作的访问者层次结构,不属于该层次结构时(如下面的示例代码中的ConfigureLeaderVisitor,ConfigureEmployeeVisitor,ConfigureAccountantVisitor)

四. 优点及缺点

  • 优点
    1. 对于类等级体系,没有固有的依赖循环结构
    2. 添加一个新的访问者,无需修改所有的访问者
    3. 由于脱离了依赖循环,即使添加一个新的访问之编译出错,也不会影响已存在的访问者
  • 缺点
    1. 违反里斯科夫替代原则,表明它可以接受所有访客,但实际上只对特定访客感兴趣。
    2. 必须为可访问类层次结构中的所有成员创建并行访问器层次结构。

五. 无环访问者模式结构图

在这里插入图片描述

六. 小试牛刀

6.1 例子

在一个公司里,有领导,会计,员工等等不同的职位

  1. 对于领导的话,员工,会计这样的职位等级,由于领导平常里都很忙,他们是没有权限访问见面的

  2. 对于员工,会计的话,是可以相互访问见面的

那么对于这两种情况,如何实现的,如果以后公司规模变大,会有更多职位等级的出现及访问权限,又如何实现呢

对于这些情况,无环访问者很巧妙的解决了

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


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值