设计模式与插件化:工厂模式加载插件、策略模式选择插件、责任链处理插件
插件化架构,说白了就是让系统能「长」出新的功能。我做了十几年架构,最头疼的就是系统写死了,加个新功能要改核心代码。今天聊的这三种模式,正好能解决这个问题。
工厂模式负责「造」插件,策略模式负责「选」插件,责任链负责「串」插件。三者配合,能搭出一套灵活的插件系统。
一、工厂模式:插件的「生产线」
工厂模式在这里的角色,就是根据配置或参数,动态创建出对应的插件实例。我在项目中遇到过一种情况:客户要求支持多种数据源,MySQL、Oracle、MongoDB,每种数据源的连接方式完全不同。如果硬编码if-else,那代码就成了一团乱麻。
用工厂模式就清爽多了。你只需要定义一个插件接口,然后每个插件实现这个接口。工厂类根据传入的插件类型,返回对应的实例。
// Java 示例:插件工厂
public interface Plugin {
void execute();
}
public class MySQLPlugin implements Plugin {
public void execute() {
System.out.println("执行MySQL数据源插件");
}
}
public class OraclePlugin implements Plugin {
public void execute() {
System.out.println("执行Oracle数据源插件");
}
}
public class PluginFactory {
public static Plugin createPlugin(String type) {
switch (type) {
case "mysql": return new MySQLPlugin();
case "oracle": return new OraclePlugin();
default: throw new IllegalArgumentException("未知插件类型");
}
}
}
个人经验:工厂类里不要写死所有插件类型。我习惯用反射或SPI机制,让插件自己注册到工厂里。这样加新插件时,工厂代码不用改。
二、策略模式:插件的「选择器」
工厂把插件造出来了,但用哪个呢?这就轮到策略模式上场了。策略模式的核心思想是:把算法或行为封装成独立的策略类,让它们可以互相替换。
在插件系统里,策略模式用来决定「当前场景下该用哪个插件」。比如,用户上传了一个Excel文件,系统需要根据文件格式选择对应的解析插件。
// C++ 示例:策略选择器
class PluginStrategy {
public:
virtual Plugin* selectPlugin(const std::string& context) = 0;
};
class FileTypeStrategy : public PluginStrategy {
public:
Plugin* selectPlugin(const std::string& fileType) override {
if (fileType == "xlsx") return new ExcelPlugin();
if (fileType == "csv") return new CSVPlugin();
return nullptr;
}
};
你想想看,如果没有策略模式,你可能会写一堆if-else来判断文件类型。有了策略模式,每种选择逻辑都是一个独立的类,测试、扩展都方便。
核心要点:策略模式让「选择逻辑」和「业务逻辑」解耦。我曾经在一个项目中,把策略选择器做成可配置的,用户甚至可以在界面上拖拽选择策略,爽得很。
三、责任链模式:插件的「流水线」
单个插件能干活了,但很多时候需要多个插件协同工作。比如,一个请求进来,先经过日志插件记录,再经过权限校验插件检查,最后经过业务处理插件执行。
责任链模式就是干这个的。它把多个插件串成一条链,每个插件处理完自己的逻辑后,决定是否把请求传给下一个插件。
// Java 示例:责任链
public abstract class PluginHandler {
protected PluginHandler next;
public void setNext(PluginHandler next) {
this.next = next;
}
public void handle(Request request) {
if (canHandle(request)) {
process(request);
}
if (next != null) {
next.handle(request);
}
}
protected abstract boolean canHandle(Request request);
protected abstract void process(Request request);
}
public class LogPlugin extends PluginHandler {
protected boolean canHandle(Request request) {
return true; // 所有请求都记录日志
}
protected void process(Request request) {
System.out.println("记录日志:" + request.getContent());
}
}
public class AuthPlugin extends PluginHandler {
protected boolean canHandle(Request request) {
return request.needAuth();
}
protected void process(Request request) {
System.out.println("校验权限");
}
}
避坑指南:我曾经在责任链里忘了加「终止条件」,结果请求在链里无限循环,把CPU跑满了。记住:每个插件处理完后,一定要明确是否继续传递。
四、三者如何配合?
这三种模式不是孤立的。在实际项目中,它们经常一起出现。我画了一张图,帮你理清它们的关系:
五、实战中的组合用法
我参与过一个报表系统,支持多种数据源和多种输出格式。当时的设计是这样的:
- 工厂模式:根据配置加载数据源插件(MySQL、Redis、API)和输出插件(PDF、Excel、HTML)
- 策略模式:根据用户选择的报表类型,决定用哪个数据源插件和输出插件
- 责任链模式:把数据清洗、数据转换、数据输出三个插件串起来,按顺序执行
这样做的好处是:加一个新数据源,只需要写一个新插件,注册到工厂里。加一个新报表类型,只需要加一个策略。调整处理顺序,只需要改责任链的配置。
总结一下:工厂模式解决「怎么造插件」,策略模式解决「用哪个插件」,责任链模式解决「怎么串插件」。三个模式各司其职,组合起来就是一套完整的插件化架构。
嗯,这里要注意一点:不要为了用模式而用模式。如果你的系统只有两三个插件,硬上责任链反而增加复杂度。我个人的习惯是:当插件数量超过5个,或者插件的组合方式经常变化时,才考虑引入这三种模式。