设计模式-访问者模式

设计模式-访问者模式

访问者者模式的英文翻译是 Visitor Design Pattern。它是这么定义的:Allows for one or more operation to be applied to a set of objects at runtime, decoupling the operations from the object structure. 翻译成中文就是:允许一个或者多个操作应用到一组对象上,解耦操作和对象本身。

案例分析

如果有一个接口,这个接口有三个实现类,那么我们可以充分利用多态特性进行处理

java 复制代码
public interface Visit {

    void visit();

}

public class AVisitor implements Visit {

    @Override
    public void visit() {
        System.out.println("AVisitor:visit");
    }

}

public class BVisitor implements Visit {

    @Override
    public void visit() {
        System.out.println("BVisitor:visit");
    }
    
}

public class CVisitor implements Visit {
    @Override
    public void visit() {
        System.out.println("CVisitor:visit");
    }

}

由于这三个实现类都实现了该接口,因此可以借助多态特性使用

java 复制代码
public class Main {

    public static void main(String[] args) {
        List<String> types = List.of("A","B","C");
        String type = types.get(new Random().nextInt(3));
        Visit visit = new AVisitor();
        if (type.equals("A")) {
            visit = new AVisitor();
        }
        if (type.equals("B")) {
            visit = new BVisitor();
        }
        if (type.equals("C")) {
            visit = new CVisitor();
        }
        processVisit(visit);
    }

    private static void processVisit(Visit visit) {
        visit.visit();
    }

}

这也是我们经常用到的方式

但是随着接口的方法增加,所有的实现类都需要新增实现接口的内容,如果接口的内容过多,会导致实现类的内容非常庞大,那么我们可以反向思考,按照功能实现接口,还是如上的场景,例如 ABC 三个实现类都需要实现接口中的 funcation1 和 funcation2 方法,我们定义如下接口

java 复制代码
public interface Visit {

    void visit(AFuncationImpl a);

    void visit(BFuncationImpl b);

    void visit(CFuncationImpl c);

}

利用接口重载支持多个实现类,接着我们按照功能拆分为 funcation1 类 和 funcation2 类

java 复制代码
public class Funcation1Visitor implements Visit {

    @Override
    public void visit(AFuncationImpl a) {
        System.out.println("AVisitor Funcation1");
    }

    @Override
    public void visit(BFuncationImpl b) {
        System.out.println("BVisitor Funcation1");
    }

    @Override
    public void visit(CFuncationImpl c) {
        System.out.println("CVisitor Funcation1");
    }

}

public class Funcation2Visitor implements Visit {

    @Override
    public void visit(AFuncationImpl a) {
        System.out.println("AVisitor Funcation2");
    }

    @Override
    public void visit(BFuncationImpl b) {
        System.out.println("BVisitor Funcation2");
    }

    @Override
    public void visit(CFuncationImpl c) {
        System.out.println("CVisitor Funcation2");
    }

}

经过这样的拆分,可以看出每个 Funcation 中一般只有实现类个方法。

那么该如何使用呢,每一个 FuncationVisitor 的参数已经变成具体的实现类类,是不是就无法充分利用多态特性了?

我们可以再定义一个接口

java 复制代码
public interface Accept {

    void accept(Visit visit);

}

所有的 CFuncationImpl 实现这个接口,并传入具体的 FuncationVisitor,这样就能充分利用多态特性了

java 复制代码
public class AFuncationImpl implements Accept {

    @Override
    public void accept(Visit visit) {
        visit.visit(this);
    }

}

public class BFuncationImpl implements Accept {

    @Override
    public void accept(Visit visit) {
        visit.visit(this);
    }

}

public class CFuncationImpl implements Accept {

    @Override
    public void accept(Visit visit) {
        visit.visit(this);
    }

}

测试代码:

java 复制代码
public class Main {

    public static void main(String[] args) {
        List<Accept> acceptList = List.of(new AFuncationImpl(), new BFuncationImpl(), new CFuncationImpl());

        Visit visit = new Funcation1Visitor();
        for (Accept accept : acceptList) {
            accept.accept(visit);
        }

        visit = new Funcation2Visitor();
        for (Accept accept : acceptList) {
            accept.accept(visit);
        }
    }

}

类之间关系如图:

梳理一下改动的思路,由于接口中的方法越来越多会导致实现类的代码越来越多,访问者模式提供了一种思路按照功能进行抽象(Visit),利用接口重载为所有的实现类设置一个方法(Visit.visit),并让所有的功能类实现这个方法。

由于功能类实现后正常情况下无法利用多态特性(此时的参数是具体实现类),因此可以让具体实现类(AFuncationImpl、BFuncationImpl等)实现一个统一的接口(Accept)。

访问者模式为了避免不断添加功能导致类不断膨胀,职责越来越不单一,以及避免频繁地添加功能导致的频繁代码修改,将对象与操作解耦,将这些业务操作抽离出来,定义在独立细分的访问者类中。

相关推荐
崎岖Qiu2 小时前
【设计模式笔记17】:单例模式1-模式分析
java·笔记·单例模式·设计模式
安冬的码畜日常7 小时前
【JUnit实战3_27】第十六章:用 JUnit 测试 Spring 应用:通过实战案例深入理解 IoC 原理
spring·观察者模式·设计模式·单元测试·ioc·依赖注入·junit5
她说彩礼65万9 小时前
C#设计模式 单例模式实现方式
单例模式·设计模式·c#
安冬的码畜日常13 小时前
【JUnit实战3_28】第十七章:用 JUnit 5 实测 SpringBoot 项目
spring boot·功能测试·测试工具·设计模式·单元测试·junit5
围巾哥萧尘13 小时前
TRAE Agent 歌曲创作助手构建与使用教程🧣
设计模式
superman超哥13 小时前
仓颉语言中流式I/O的设计模式深度剖析
开发语言·后端·设计模式·仓颉
m0_7482480215 小时前
Spring设计模式刨根问底
java·spring·设计模式
不要额外加糖16 小时前
tql,寥寥几行,实现无队列无感刷新
前端·javascript·设计模式
ACGkaka_16 小时前
设计模式学习(十二)状态模式
学习·设计模式·状态模式
乐悠小码17 小时前
Java设计模式精讲---01工厂方法模式
java·设计模式·工厂方法模式