设计模式与插件化:工厂模式加载插件、策略模式选择插件、责任链处理插件

插件化架构,说白了就是让系统能「长」出新的功能。我做了十几年架构,最头疼的就是系统写死了,加个新功能要改核心代码。今天聊的这三种模式,正好能解决这个问题。

工厂模式负责「造」插件,策略模式负责「选」插件,责任链负责「串」插件。三者配合,能搭出一套灵活的插件系统。

一、工厂模式:插件的「生产线」

工厂模式在这里的角色,就是根据配置或参数,动态创建出对应的插件实例。我在项目中遇到过一种情况:客户要求支持多种数据源,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跑满了。记住:每个插件处理完后,一定要明确是否继续传递。

四、三者如何配合?

这三种模式不是孤立的。在实际项目中,它们经常一起出现。我画了一张图,帮你理清它们的关系:

工厂模式 + 策略模式 + 责任链模式 协作图 工厂模式 根据类型创建插件 PluginFactory.create() 输出:插件实例 策略模式 根据上下文选择插件 PluginStrategy.select() 输出:选中的插件 责任链模式 串联多个插件处理 PluginHandler.handle() 输出:处理结果 典型执行流程 1. 系统启动时,工厂模式加载所有可用插件 2. 请求到达时,策略模式根据上下文选择合适插件 3. 选中的插件被加入责任链,按顺序处理请求 4. 每个插件处理完,决定是否传递给下一个插件 三者配合:工厂负责创建,策略负责选择,责任链负责编排

五、实战中的组合用法

我参与过一个报表系统,支持多种数据源和多种输出格式。当时的设计是这样的:

  1. 工厂模式:根据配置加载数据源插件(MySQL、Redis、API)和输出插件(PDF、Excel、HTML)
  2. 策略模式:根据用户选择的报表类型,决定用哪个数据源插件和输出插件
  3. 责任链模式:把数据清洗、数据转换、数据输出三个插件串起来,按顺序执行

这样做的好处是:加一个新数据源,只需要写一个新插件,注册到工厂里。加一个新报表类型,只需要加一个策略。调整处理顺序,只需要改责任链的配置。

总结一下:工厂模式解决「怎么造插件」,策略模式解决「用哪个插件」,责任链模式解决「怎么串插件」。三个模式各司其职,组合起来就是一套完整的插件化架构。

嗯,这里要注意一点:不要为了用模式而用模式。如果你的系统只有两三个插件,硬上责任链反而增加复杂度。我个人的习惯是:当插件数量超过5个,或者插件的组合方式经常变化时,才考虑引入这三种模式。

公众号:蓝海资料掘金营,微信deep3321