一、背景
最近需要调研如何将 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 提取出来。这是一个可能的代码示例:
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 中使用了访问者模来实现这部分功能。 于是,我们趁机学习一下访问者模式吧。
访问者模式是一种行为型设计模式,它可以让你在不修改对象结构的情况下,为对象结构中的元素添加新的操作。 访问者模式的应用场景是:
一个典型的例子是 Java 的 ASM 库,它可以用来操作字节码。ASM 提供了一个抽象的访问者接口,让用户可以自定义访问者类来实现对字节码的各种操作,例如修改、增加、删除、优化等。这样,ASM 就可以保持其核心功能的稳定性,同时提供了灵活的扩展性。
有两种类型的游戏:收费游戏和免费游戏,它们都是被访问者。 有两种类型的玩家:付费玩家和免费玩家,它们都是访问者。 不同类型的玩家对不同类型的游戏有不同的操作,例如付费玩家可以下载收费游戏,而免费玩家只能试玩收费游戏。这些操作都是通过访问者模式来实现的,代码如下:
// 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);
}
}
输出结果为:
付费玩家可以下载收费游戏:英雄联盟,价格为:99.9
付费玩家可以下载免费游戏:消消乐,价格为:0.0
免费玩家只能试玩收费游戏:英雄联盟,价格为:99.9
免费玩家可以下载免费游戏:消消乐,价格为:0.0
访问者模式的优点有:
访问者模式的缺点有:
大家在日常开发中见到某种设计模式的影子时,可以去源码中学习该功能是如何使用该设计模式来实现的。主动重温该设计模式的适用场景,该设计模式的优点和缺点。这样才能够对该设计模式理解更加深刻,才更容易在未来遇到相关场景时想到该设计模式并加以致用。