2_软件重构_一种组件化开发方式

发布于:2025-07-29 ⋅ 阅读:(18) ⋅ 点赞:(0)

一、碎碎念       

首先先考虑下,什么情况下软件需要重构?我觉得答案有很多种,而且还有范围。当日益增长的需求与现有软件结构越来越无法匹配时——①具体表现可能为新增需求所导致的bug越来越多,一个新功能的改动牵一发而动全身,需要对代码较为熟悉才能修改;②现有软件结构无法满足一些新需求,软件结构设计之初未考虑,后续改动工程量巨大③新老员工多人维护代码,代码走读形同虚设,代码越来越乱 .        

最后产品在残酷的市场竞争中存活了下来,面对着越来越离谱的代码,需要着手重构了。面对这一坨代码,是在现有代码上重构,还是直接推导重做不兼容,看具体情况了。一般只有行业头部的公司才会搞重构,小公司正忙着生存。

结合上篇文章软件插件化,选用里面最后一种方式,将每个模块作为一个动态库,理清各个模块之间的调用关系,将整体代码重新梳理解耦来实现“重构”。突然想到,我们每一个个体,正如这一坨坨的代码,只有先生存了下去,才有机会考虑是否能重构自我,还怪残酷的咧~头部公司可以投入资源去搞重构,而小公司往往就没这样的机会了。

二、插件(组件、中间件)化代码框架

1、接口定义(核心头文件)

// plugin_interface.h#ifndef PLUGIN_INTERFACE_H#define PLUGIN_INTERFACE_H class Plugin {public:    virtual ~Plugin() {}  // 必须要有虚析构函数    virtual void initialize() = 0;    virtual void execute(const std::string& params) = 0;    virtual const char* name() const = 0;}; // 定义插件创建和销毁的函数指针类型extern "C" {    typedef Plugin* (*CreatePluginFunc)();    typedef void (*DestroyPluginFunc)(Plugin*);} #endif

2、插件实现(编写具体插件)

// demo_plugin.cpp#include "plugin_interface.h"#include class DemoPlugin : public Plugin {public:    void initialize() override {        std::cout << "DemoPlugin initialized\n";    }        void execute(const std::string& params) override {        std::cout << "Executing with params: " << params << "\n";    }        const char* name() const override {        return "DemoPlugin v1.0";    }};
// 导出C接口的创建/销毁函数extern "C" {    Plugin* create_plugin() {        return new DemoPlugin();    }        void destroy_plugin(Plugin* p) {        delete p;    }}

3、主程序(动态加载插件)

// main.cpp#include "plugin_interface.h"#include#include#include int main() {    // 1. 加载动态库    void* handle = dlopen("./demo_plugin.so", RTLD_LAZY);    if (!handle) {        std::cerr << "Error loading plugin: " << dlerror() << std::endl;        return 1;    }     // 2. 获取符号地址    auto create = (CreatePluginFunc)dlsym(handle, "create_plugin");    auto destroy = (DestroyPluginFunc)dlsym(handle, "destroy_plugin");        if (!create || !destroy) {        std::cerr << "Error loading symbols: " << dlerror() << std::endl;        dlclose(handle);        return 1;    }     // 3. 创建插件实例    std::unique_ptr<Plugin, </Plugin,void(*)(Plugin*)> plugin(create(), destroy);        // 4. 使用插件功能    plugin->initialize();    plugin->execute("test_parameters");    std::cout << "Plugin name: " << plugin->name() << std::endl;     // 5. 自动释放资源(通过unique_ptr)    dlclose(handle);    return 0;}

4、编译与运行

4.1 编译插件(生成 .so 文件)

g++ -fPIC -shared -o demo_plugin.so demo_plugin.cpp

4.2 编译主程序

g++ main.cpp -o main -ldl

4.3 运行程序

./main# 输出:# DemoPlugin initialized# Executing with params: test_parameters# Plugin name: DemoPlugin v1.0

三、关键点解析

1. ABI 兼容性

使用 extern "C" 确保符号名称不被改编

保持接口头文件稳定(修改后需重新编译所有插件)

2. 资源管理

使用 unique_ptr + 自定义删除器自动管理插件生命周期

必须通过插件的 destroy_plugin 释放内存

3. 错误处理

检查 dlopen 和 dlsym 返回值

使用 dlerror() 获取详细错误信息

欢迎关注,下次分享一个实际使用的例子。


网站公告

今日签到

点亮在社区的每一天
去签到