设计模式-访问者模式

设计模式-访问者模式

访问者者模式的英文翻译是 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)。

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

相关推荐
廋到被风吹走8 小时前
【Java】常用设计模式及应用场景详解
java·开发语言·设计模式
Jaycee青橙11 小时前
软件设计模式详解
设计模式
alibli15 小时前
一文学会设计模式之结构型模式及最佳实现
c++·设计模式
联系QQ 192263815 小时前
探索高压直流输电MATLAB/simulink模型及换相失败相关要点
访问者模式
电子科技圈18 小时前
SiFive车规级RISC-V IP获IAR最新版嵌入式开发工具全面支持,加速汽车电子创新
嵌入式硬件·tcp/ip·设计模式·汽车·代码规范·risc-v·代码复审
七月丶20 小时前
Cloudflare 🌏 中国大陆网络访问优化 - 0元成本
人工智能·react.js·设计模式
老朱佩琪!20 小时前
Unity访问者模式
unity·游戏引擎·访问者模式
筏.k20 小时前
C++ 设计模式系列:单例模式
c++·单例模式·设计模式
__万波__20 小时前
二十三种设计模式(十二)--代理模式
java·设计模式·代理模式
郝学胜-神的一滴21 小时前
Linux线程编程:从原理到实践
linux·服务器·开发语言·c++·程序人生·设计模式·软件工程