Go和Java实现访问者模式

Go和Java实现访问者模式

我们下面通过一个解压和压缩各种类型的文件的案例来说明访问者模式的使用。

1、访问者模式

在访问者模式中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随

着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者

对象就可以处理元素对象上的操作。

  • 意图:主要将数据结构与数据操作分离。

  • 主要解决:稳定的数据结构和易变的操作耦合问题。

  • 何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这

    些对象的类,使用访问者模式将这些封装到类中。

  • 如何解决:在被访问的类里面加一个对外提供接待访问者的接口。

  • 关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。

  • 应用实例:您在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一

    个判断,这就是访问者模式。

  • 优点:1、符合单一职责原则。 2、优秀的扩展性。 3、灵活性。

  • 缺点:1、具体元素对访问者公布细节,违反了迪米特原则。 2、具体元素变更比较困难。 3、违反了依赖倒

    置原则,依赖了具体类,没有依赖抽象。

  • 使用场景:1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。 2、需要对一

    个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希

    望在增加新操作时修改这些类。

  • 注意事项:访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。

  • 适用性:

    一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。

    需要对一个对象结构中的对象进行很多不同的并且不相关的操作,让你想避免让这些操作污染这些对象的类。

    Visitor使得你可以将相关的操作集中起来定义在一个类中,当该对象结构被很多应用共享时,用Visitor模

    式让每个应用仅包含需要用到的操作。

    定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者

    的接口,这可能想要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。

2、Go实现访问者模式

go 复制代码
package visitor

// ========== 访问者FileUseVisitor ==========
type FileUseVisitor interface {

	// 为每一个类声明一个visit操作
	visitPdfFile(FileResourceVisitable)

	visitPPTFile(FileResourceVisitable)

	visitTextFile(FileResourceVisitable)
}
go 复制代码
package visitor

import "fmt"

// ========== 访问者Compress ==========
type Compress struct {
}

func (compress *Compress) visitPdfFile(fileResourceVisitable FileResourceVisitable) {
	fmt.Println("Compress file: " + fileResourceVisitable.(*PdfFile).Path)
}

func (compress *Compress) visitPPTFile(fileResourceVisitable FileResourceVisitable) {
	fmt.Println("Compress file: " + fileResourceVisitable.(*PPTFile).Path)
}

func (compress *Compress) visitTextFile(fileResourceVisitable FileResourceVisitable) {
	fmt.Println("Compress file: " + fileResourceVisitable.(*TextFile).Path)
}
go 复制代码
package visitor

import "fmt"

// ========== 访问者Decompress ==========
type Decompress struct {
}

func (decompress *Decompress) visitPdfFile(fileResourceVisitable FileResourceVisitable) {
	fmt.Println("Decompress file: " + fileResourceVisitable.(*PdfFile).Path)
}

func (decompress *Decompress) visitPPTFile(fileResourceVisitable FileResourceVisitable) {
	fmt.Println("Decompress file: " + fileResourceVisitable.(*PPTFile).Path)
}

func (decompress *Decompress) visitTextFile(fileResourceVisitable FileResourceVisitable) {
	fmt.Println("Decompress file: " + fileResourceVisitable.(*TextFile).Path)
}
go 复制代码
package visitor

// ========== 接收者FileResourceVisitable ==========
type FileResourceVisitable interface {
	accept(FileUseVisitor)
}
go 复制代码
package visitor

// ========== 接收者PdfFile ==========
type PdfFile struct {
	Path string
}

func (pdfFile *PdfFile) accept(fileUseVisitor FileUseVisitor) {
	fileUseVisitor.visitPdfFile(pdfFile)
}
go 复制代码
package visitor

// ========== 接收者PPTFile ==========
type PPTFile struct {
	Path string
}

func (pPTFile *PPTFile) accept(fileUseVisitor FileUseVisitor) {
	fileUseVisitor.visitPPTFile(pPTFile)
}
go 复制代码
package visitor

// ========== 接收者TextFile ==========
type TextFile struct {
	Path string
}

func (textFile *TextFile) accept(fileUseVisitor FileUseVisitor) {
	fileUseVisitor.visitTextFile(textFile)
}
go 复制代码
package visitor

// ========== FileStructure ==========
type FileStructure struct {
	fileResourceVisitableList []FileResourceVisitable
}

func (fileStructure *FileStructure) Attach(fileResourceVisitable FileResourceVisitable) {
	fileStructure.fileResourceVisitableList = append(fileStructure.fileResourceVisitableList, fileResourceVisitable)
}

func (fileStructure *FileStructure) Detach(fileResourceVisitable FileResourceVisitable) {
	for i := 0; i < len(fileStructure.fileResourceVisitableList); i++ {
		if fileStructure.fileResourceVisitableList[i] == fileResourceVisitable {
			fileStructure.fileResourceVisitableList = append(fileStructure.fileResourceVisitableList[:i], fileStructure.fileResourceVisitableList[i+1:]...)
		}
	}
}

func (fileStructure *FileStructure) Accept(fileUseVisitor FileUseVisitor) {
	for _, fileResourceVisitable := range fileStructure.fileResourceVisitableList {
		fileResourceVisitable.accept(fileUseVisitor)
	}
}
go 复制代码
package main

import . "proj/visitor"

func main() {
	fileStructure := FileStructure{}
	fileStructure.Attach(&PPTFile{Path: "test.ppt"})
	fileStructure.Attach(&PdfFile{Path: "test.pdf"})
	fileStructure.Attach(&TextFile{Path: "test.txt"})
	fileStructure.Accept(&Decompress{})
	fileStructure.Accept(&Compress{})
}
shell 复制代码
# 输出
Decompress file: test.ppt
Decompress file: test.pdf
Decompress file: test.txt
Compress file: test.ppt
Compress file: test.pdf
Compress file: test.txt

3、Java实现访问者模式

java 复制代码
package com.visitor;

// ========== 访问者FileUseVisitor ==========
public interface FileUseVisitor {

    // 为每一个类声明一个visit操作
    void visitPdfFile(FileResourceVisitable fileResourceVisitable);

    void visitPPTFile(FileResourceVisitable fileResourceVisitable);

    void visitTextFile(FileResourceVisitable fileResourceVisitable);
}
java 复制代码
package com.visitor;

// ========== 访问者Compress ==========
public class Compress implements FileUseVisitor{

    @Override
    public void visitPdfFile(FileResourceVisitable fileResourceVisitable) {
        System.out.println("Compress file: "+fileResourceVisitable.path);
    }

    @Override
    public void visitPPTFile(FileResourceVisitable fileResourceVisitable) {
        System.out.println("Compress file: "+fileResourceVisitable.path);
    }

    @Override
    public void visitTextFile(FileResourceVisitable fileResourceVisitable) {
        System.out.println("Compress file: "+fileResourceVisitable.path);
    }
}
java 复制代码
package com.visitor;

// ========== 访问者Decompress ==========
public class Decompress implements FileUseVisitor{

    @Override
    public void visitPdfFile(FileResourceVisitable fileResourceVisitable) {
        System.out.println("Decompress file: "+fileResourceVisitable.path);
    }

    @Override
    public void visitPPTFile(FileResourceVisitable fileResourceVisitable) {
        System.out.println("Decompress file: "+fileResourceVisitable.path);
    }

    @Override
    public void visitTextFile(FileResourceVisitable fileResourceVisitable) {
        System.out.println("Decompress file: "+fileResourceVisitable.path);
    }
}
java 复制代码
package com.visitor;

// ========== 接收者FileResourceVisitable ==========
public abstract class FileResourceVisitable {
    protected String path;
    abstract void accept(FileUseVisitor fileUseVisitor);
}
java 复制代码
package com.visitor;

// ========== 接收者PdfFile ==========
public class PdfFile extends FileResourceVisitable {

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

    @Override
    public void accept(FileUseVisitor fileUseVisitor) {
        fileUseVisitor.visitPdfFile(this);
    }
}
java 复制代码
package com.visitor;

// ========== 接收者PPTFile ==========
public class PPTFile extends FileResourceVisitable {

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

    @Override
    public void accept(FileUseVisitor fileUseVisitor) {
        fileUseVisitor.visitPPTFile(this);
    }
}
java 复制代码
package com.visitor;

// ========== 接收者TextFile ==========
public class TextFile extends FileResourceVisitable {

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

    @Override
    public void accept(FileUseVisitor fileUseVisitor) {
        fileUseVisitor.visitTextFile(this);
    }
}
java 复制代码
package com.visitor;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

// ========== FileStructure ==========
public class FileStructure {
    List<FileResourceVisitable> fileResourceVisitableList = new ArrayList<>();

    public void attach(FileResourceVisitable fileResourceVisitable){
        fileResourceVisitableList.add(fileResourceVisitable);
    }

    public void detach(FileResourceVisitable fileResourceVisitable){
        Objects.requireNonNull(fileResourceVisitable);
    }

    public void accept(FileUseVisitor fileUseVisitor){
        for(FileResourceVisitable fileResourceVisitable:fileResourceVisitableList){
            fileResourceVisitable.accept(fileUseVisitor);
        }
    }
}
java 复制代码
package com.visitor;

public class Test {
    public static void main(String[] args) {
        FileStructure fileStructure = new FileStructure();
        fileStructure.attach(new PPTFile("test.pdf"));
        fileStructure.attach(new PdfFile("test.pdf"));
        fileStructure.attach(new TextFile("test.txt"));
        fileStructure.accept(new Compress());
        fileStructure.accept(new Decompress());
    }
}
shell 复制代码
# 输出
Compress file: test.pdf
Compress file: test.pdf
Compress file: test.txt
Decompress file: test.pdf
Decompress file: test.pdf
Decompress file: test.txt
相关推荐
Chan161 分钟前
【 SpringCloud | 微服务 MQ基础 】
java·spring·spring cloud·微服务·云原生·rabbitmq
LucianaiB4 分钟前
如何做好一份优秀的技术文档:专业指南与最佳实践
android·java·数据库
面朝大海,春不暖,花不开28 分钟前
自定义Spring Boot Starter的全面指南
java·spring boot·后端
得过且过的勇者y28 分钟前
Java安全点safepoint
java
夜晚回家1 小时前
「Java基本语法」代码格式与注释规范
java·开发语言
斯普信云原生组1 小时前
Docker构建自定义的镜像
java·spring cloud·docker
wangjinjin1801 小时前
使用 IntelliJ IDEA 安装通义灵码(TONGYI Lingma)插件,进行后端 Java Spring Boot 项目的用户用例生成及常见问题处理
java·spring boot·intellij-idea
wtg44521 小时前
使用 Rest-Assured 和 TestNG 进行购物车功能的 API 自动化测试
java
白宇横流学长2 小时前
基于SpringBoot实现的大创管理系统设计与实现【源码+文档】
java·spring boot·后端
fat house cat_2 小时前
【redis】线程IO模型
java·redis