前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >十七、访问者模式

十七、访问者模式

作者头像
Yuyy
发布2022-09-21 10:03:20
1810
发布2022-09-21 10:03:20
举报
文章被收录于专栏:yuyy.info技术专栏

Visitor pattern

因为它难理解、难实现,应用它会导致代码的可读性、可维护性变差,所以,访问者模式在实际的软件开发中很少被用到,在没有特别必要的情况下,建议你不要使用访问者模式。 ——设计模式之美

前言

这个模式侧重代码实现,主要是解决分离业务代码,抽取能力带来的问题。

示例V1

模拟读取不同格式的文件。

TextFileV1
TextFileV1

ResourceFileV1:资源文件抽象类

定义文件相关的操作

代码语言:javascript
复制
public abstract class ResourceFileV1 {
    private String path;

    public ResourceFileV1(String path) {
        this.path = path;
    }

    public abstract void read();
}

PdfFileV1:Pdf文件处理类

代码语言:javascript
复制
public class PdfFileV1 extends ResourceFileV1 {

    public PdfFileV1(String path) {
        super(path);
    }

    @Override
    public void read() {
        System.out.println("读取Pdf文件内容");
    }
}

TextFileV1:文本文件处理类

代码语言:javascript
复制
public class TextFileV1 extends ResourceFileV1 {

    public TextFileV1(String path) {
        super(path);
    }

    @Override
    public void read() {
        System.out.println("读取Text文件内容");
    }
}

使用

代码语言:javascript
复制
    @Test
    public void testV1() {
        final List<ResourceFileV1> resourceFileV1s = buildResourceFiles();
        resourceFileV1s.forEach(ResourceFileV1::read);
    }

    public List<ResourceFileV1> buildResourceFiles() {
        return Lists.newArrayList(new PdfFileV1("xx"),
                                  new TextFileV1("xx"));

    }

存在的问题

如果需求简单,就是针对不同格式的文件简单处理,那上诉设计是没问题的。

但是如果处理操作很多,文件类处理处理文件还有其他业务代码,这时就会造成文件类臃肿,不符合单一职责原则。每增加一种文件处理操作,就需要修改上诉所有类,不符合开闭原则(这句话不是那么绝对,所有原则都要视情况而定)。

重构优化V2

将文件处理能力独立出来,利用重载来处理各种格式的文件。

PdfFileV2
PdfFileV2

Reader:读取文件

代码语言:javascript
复制
public class Reader {

    public void read(PdfFileV2 pdfFileV2) {
        System.out.println("读取Pdf文件内容");
    }

    public void read(TextFileV2 textFileV2) {
        System.out.println("读取Pdf文件内容");
    }
}

使用

代码语言:javascript
复制
@Test
public void testV2() {
    final List<ResourceFileV2> resourceFileV2s = buildResourceFilesV2();
    resourceFileV2s.forEach(Reader::read);
}

编译前第4行报错

image-20211011112719662
image-20211011112719662

原因是方法重载需要在编译时确认,不能像多态那样,运行时确认。

重构优化V3

不能通过resourceFile确定调用哪个重载方法,但是在PdfFile里是能确定的。

TextFileV3
TextFileV3

PdfFileV3

代码语言:javascript
复制
public class PdfFileV3 extends ResourceFileV3 {

    public PdfFileV3(String path) {
        super(path);
    }

    @Override
    public void read(ReaderV3 readerV3) {
        readerV3.read(this);
    }

}

使用

代码语言:javascript
复制
    @Test
    public void testV3() {
        final ReaderV3 readerV3 = new ReaderV3();
        final List<ResourceFileV3> resourceFileV3s = buildResourceFilesV3();
        resourceFileV3s.forEach(resourceFileV3 -> resourceFileV3.read(readerV3));
    }

存在的问题

这是不是和重构前的V1版本很像,并且每增加一种文件操作都得修改所有文件类。

CompressV3:压缩文件

代码语言:javascript
复制
public class CompressV3 {

    public void compress(PdfFileV3 pdfFileV3) {
        System.out.println("压缩Pdf文件");
    }

    public void compress(TextFileV3 textFileV2) {
        System.out.println("压缩Pdf文件");
    }
}

PdfFileV3:增加压缩方法

代码语言:javascript
复制
public class PdfFileV3 extends ResourceFileV3 {

    public PdfFileV3(String path) {
        super(path);
    }

    @Override
    public void read(ReaderV3 readerV3) {
        readerV3.read(this);
    }

    @Override
    public void compress(CompressV3 compressV3) {
        compressV3.compress(this);
    }

}

我们是在白费功夫吗?肯定不是,咋们接着优化。

仔细看看这两个能力类,都只有一个能力方法,可否抽象下,解决文件类使用能力时需新增方法的问题。

重构优化V4

PdfFileV4
PdfFileV4

VisitorV4:访问者接口

访问不同格式的文件

代码语言:javascript
复制
public interface VisitorV4 {
    void visit(PdfFileV4 pdfFileV4);

    void visit(TextFileV4 textFileV4);
}

ReaderV4:读取文件

代码语言:javascript
复制
public class ReaderV4 implements VisitorV4 {

    @Override
    public void visit(PdfFileV4 pdfFileV4) {
        System.out.println("读取Pdf文件内容");
    }

    @Override
    public void visit(TextFileV4 textFileV4) {
        System.out.println("读取Pdf文件内容");
    }

}

CompressV4:压缩文件

代码语言:javascript
复制
public class CompressV4 implements VisitorV4 {
    @Override
    public void visit(PdfFileV4 pdfFileV4) {
        System.out.println("压缩Pdf文件");
    }

    @Override
    public void visit(TextFileV4 textFileV4) {
        System.out.println("压缩Pdf文件");
    }
}

ResourceFileV4:资源文件抽象父类

代码语言:javascript
复制
public abstract class ResourceFileV4 {
    private String path;

    public ResourceFileV4(String path) {
        this.path = path;
    }

    public abstract void visit(VisitorV4 visitorV4);
}

PdfFileV4:Pdf文件处理类

代码语言:javascript
复制
public class PdfFileV4 extends ResourceFileV4 {

    public PdfFileV4(String path) {
        super(path);
    }

    @Override
    public void visit(VisitorV4 visitorV4) {
        visitorV4.visit(this);
    }
}

TextFileV4:文本文件处理类

代码语言:javascript
复制
public class TextFileV4 extends ResourceFileV4 {

    public TextFileV4(String path) {
        super(path);
    }

    @Override
    public void visit(VisitorV4 visitorV4) {
        visitorV4.visit(this);
    }
}

使用

代码语言:javascript
复制
@Test
public void testV4() {
    final ReaderV4 readerV4 = new ReaderV4();
    final CompressV4 compressV4 = new CompressV4();
    final List<ResourceFileV4> resourceFileV4s = buildResourceFilesV4();
    resourceFileV4s.forEach(resourceFileV4 -> {
        resourceFileV4.visit(readerV4);
        resourceFileV4.visit(compressV4);
    });
}

总结

访问者模式的演进过程复杂,直接看代码很难理解用意。而且从使用场景来看,使用策略模式也能达到目的,并且更好理解。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-10-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Visitor pattern
    • 前言
      • 示例V1
        • ResourceFileV1:资源文件抽象类
        • PdfFileV1:Pdf文件处理类
        • TextFileV1:文本文件处理类
        • 使用
        • 存在的问题
      • 重构优化V2
        • Reader:读取文件
        • 使用
        • 编译前第4行报错
      • 重构优化V3
        • PdfFileV3
        • 使用
        • 存在的问题
        • CompressV3:压缩文件
        • PdfFileV3:增加压缩方法
      • 重构优化V4
        • VisitorV4:访问者接口
        • ReaderV4:读取文件
        • CompressV4:压缩文件
        • ResourceFileV4:资源文件抽象父类
        • PdfFileV4:Pdf文件处理类
        • TextFileV4:文本文件处理类
        • 使用
      • 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档