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

我用 ChatGPT 学设计模式之访问者模式

作者头像
明明如月学长
发布2023-04-30 14:40:52
2450
发布2023-04-30 14:40:52
举报
文章被收录于专栏:明明如月的技术专栏

一、背景

最近需要调研如何将 SQL 中的表名解析出来。 通过对 New Bing 不断提问,得知 com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser可以实现这个功能。

继续对 New Bing 进行提问,让 New Bing 帮我们写出 Demo 代码:

在这里插入图片描述
在这里插入图片描述

能不能使用Java 语言,借助 com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser 将下面的 SQL 中 表名 user 提取出来, SQL : select * form user where userId =10086。

New Bing 的回复:可以使用 Java 语言,借助 com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser 将 SQL 中的表名 user 提取出来。这是一个可能的代码示例:

代码语言:javascript
复制
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;

public class Main {
    public static void main(String[] args) {
        String sql = "select * from user where userId = 10086";
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLStatement statement = parser.parseStatement();
        SchemaStatVisitor visitor = new SchemaStatVisitor();
        statement.accept(visitor);
        System.out.println(visitor.getTables().keySet()); // 输出 [user]
    }
}

从这份代码中我们发现, druid 中使用了访问者模来实现这部分功能。 于是,我们趁机学习一下访问者模式吧。

二、访问者模式

2.1 使用场景

访问者模式是一种行为型设计模式,它可以让你在不修改对象结构的情况下,为对象结构中的元素添加新的操作。 访问者模式的应用场景是:

  • 当你有一个复杂的对象结构(例如一个对象树),并且想在不改变这个结构的前提下,对其中的元素执行不同的操作,而且这些操作可能随着时间的推移而发生变化。
  • 当你想将一些与数据结构无关的行为封装到一个类中,而不是分散在多个类中,从而提高代码的可维护性和复用性。

一个典型的例子是 Java 的 ASM 库,它可以用来操作字节码。ASM 提供了一个抽象的访问者接口,让用户可以自定义访问者类来实现对字节码的各种操作,例如修改、增加、删除、优化等。这样,ASM 就可以保持其核心功能的稳定性,同时提供了灵活的扩展性。

2.2 代码示例

有两种类型的游戏:收费游戏和免费游戏,它们都是被访问者。 有两种类型的玩家:付费玩家和免费玩家,它们都是访问者。 不同类型的玩家对不同类型的游戏有不同的操作,例如付费玩家可以下载收费游戏,而免费玩家只能试玩收费游戏。这些操作都是通过访问者模式来实现的,代码如下:

代码语言:javascript
复制
// Game 父类 ( 被访问者 )
public abstract class Game {
    // 游戏名称
    private String name;
    // 游戏价格
    private double price;

    public Game(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    // 接受访问者的访问
    public abstract void accept(IVisitor visitor);
}

// VipGame 收费游戏 ( 被访问者 )
public class VipGame extends Game {

    public VipGame(String name, double price) {
        super(name, price);
    }

    @Override
    public void accept(IVisitor visitor) {
        // 调用访问者的访问方法
        visitor.visit(this);
    }
}

// FreeGame 免费游戏 ( 被访问者 )
public class FreeGame extends Game {

    public FreeGame(String name, double price) {
        super(name, price);
    }

    @Override
    public void accept(IVisitor visitor) {
        // 调用访问者的访问方法
        visitor.visit(this);
    }
}

// IVisitor 访问者接口
public interface IVisitor {
    // 访问收费游戏
    void visit(VipGame vipGame);
    // 访问免费游戏
    void visit(FreeGame freeGame);
}

// VipVisitor 付费玩家 ( 访问者 )
public class VipVisitor implements IVisitor {

    @Override
    public void visit(VipGame vipGame) {
        System.out.println("付费玩家可以下载收费游戏:" + vipGame.getName() + ",价格为:" + vipGame.getPrice());
    }

    @Override
    public void visit(FreeGame freeGame) {
        System.out.println("付费玩家可以下载免费游戏:" + freeGame.getName() + ",价格为:" + freeGame.getPrice());
    }
}

// FreeVisitor 免费玩家 ( 访问者 )
public class FreeVisitor implements IVisitor {

    @Override
    public void visit(VipGame vipGame) {
        System.out.println("免费玩家只能试玩收费游戏:" + vipGame.getName() + ",价格为:" + vipGame.getPrice());
    }

    @Override
    public void visit(FreeGame freeGame) {
        System.out.println("免费玩家可以下载免费游戏:" + freeGame.getName() + ",价格为:" + freeGame.getPrice());
    }
}

// 测试类
public class Test {

    public static void main(String[] args) {
        // 创建两个游戏对象
        Game vipGame = new VipGame("英雄联盟", 99.9);
        Game freeGame = new FreeGame("消消乐", 0);

        // 创建两个玩家对象
        IVisitor vipVisitor = new VipVisitor();
        IVisitor freeVisitor = new FreeVisitor();

        // 付费玩家访问两个游戏对象
        vipVisitor.visit(vipGame);
        vipVisitor.visit(freeGame);

        // 免费玩家访问两个游戏对象
        freeVisitor.visit(vipGame);
        freeVisitor.visit(freeGame);
    }
}

输出结果为:

代码语言:javascript
复制
付费玩家可以下载收费游戏:英雄联盟,价格为:99.9
付费玩家可以下载免费游戏:消消乐,价格为:0.0
免费玩家只能试玩收费游戏:英雄联盟,价格为:99.9
免费玩家可以下载免费游戏:消消乐,价格为:0.0

2.3 优、缺点

访问者模式的优点有:

  • 可以将与数据结构无关的操作封装到访问者类中,从而实现了操作和数据结构的分离,提高了代码的可维护性和复用性
  • 可以在不修改数据结构的前提下,为数据结构添加新的操作,提高了系统的扩展性
  • 可以利用双分派技术,实现多态和动态绑定

访问者模式的缺点有:

  • 增加了系统的复杂性,需要定义访问者接口和具体访问者类,以及被访问者的抽象类和具体类。
  • 违反了迪米特原则,访问者需要暴露被访问者的细节,从而降低了系统的封装性。
  • 增加了耦合,如果数据结构发生变化,需要修改所有的访问者类,降低了系统的稳定性。

四、总结

大家在日常开发中见到某种设计模式的影子时,可以去源码中学习该功能是如何使用该设计模式来实现的。主动重温该设计模式的适用场景,该设计模式的优点和缺点。这样才能够对该设计模式理解更加深刻,才更容易在未来遇到相关场景时想到该设计模式并加以致用。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 二、访问者模式
    • 2.1 使用场景
      • 2.2 代码示例
        • 2.3 优、缺点
        • 四、总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档