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

一、碎碎念       

首先先考虑下,什么情况下软件需要重构?我觉得答案有很多种,而且还有范围。当日益增长的需求与现有软件结构越来越无法匹配时——①具体表现可能为新增需求所导致的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() 获取详细错误信息

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/90858.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/90858.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

今日行情明日机会——20250728

上证指数量能持续在200天均量线上&#xff0c;最近今天横盘震荡&#xff0c;今天依然收在5天均线上方&#xff0c;个股涨跌个数基本相同。目前依然强势&#xff0c;有望冲击3674的前高。需要注意板块的高低切换。深证指数今天缩量收小阳线&#xff0c;均线多头的趋势明显&#…

【iOS】类和分类的加载过程

目录 前言 _objc_init方法 environ_init tis->init方法 static_init方法 &#x1f4a1; _objc_init 是由 libc 调用的&#xff0c;目的是&#xff1a; ❗️“必须自己实现” 是什么意思&#xff1f; runtime_init exception_init cache_t::init _imp_implementati…

大模型算法面试笔记——常用优化器SGD,Momentum,Adagrad,RMSProp,Adam

常用参数&#xff1a;ttt-步数&#xff0c;α\alphaα-学习率&#xff0c;θ\thetaθ-参数&#xff0c;f(θ)f(\theta)f(θ)-目标函数&#xff0c;gtg_tgt​-梯度&#xff0c;β1\beta_1β1​-一阶矩衰减系数&#xff0c;通常取0.9&#xff0c;β2\beta_2β2​-二阶矩&#xff…

【计算机毕业设计】基于SSM的小型超市管理系统+LW

博主介绍&#xff1a;✌全网粉丝3W,csdn特邀作者、CSDN新星计划导师、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、…

火线、零线、地线

我们可以用 “水流” 来比喻 “电流”&#xff0c;这样理解起来会很简单&#xff1a;想象一下你家的电路就像一个 “闭合的水循环系统”&#xff1a;&#x1f525; 1. 火线 (Live Wire) - 好比 “进水管的高压端”作用&#xff1a; 从发电厂或变压器输送 高压电 到你家的插座或…

基于Vue3.0+Express的前后端分离的任务清单管理系统

文章目录 一、前端 0、项目介绍 0.1 主要功能介绍 0.2 UI展示 1、首页 2、待办事项管理 2.1 添加待办事项 2.2 展示待办事项 2.3 修改待办事项 2.4 删除待办事项 3、分类管理 3.1 添加分类 3.2 展示分类 3.3 修改分类 3.4 删除分类 4、团队成员管理 4.1 展示团队成员 二、后端 …

基于单片机智能交通灯设计

传送门 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品题目速选一览表 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品题目功能速览 概述 随着城市化进程的加快&#xff0c;城市交通流量日益增大&#xff0c;传统的固定配时交通灯已难以…

Datawhale AI夏令营——列车信息智能问答——科大讯飞AI大赛(基于结构化数据的用户意图理解和知识问答挑战赛)

前言 坐火车的你&#xff0c;遇到过这样的场景吗&#xff1f; 一次又一次查车次信息&#xff1f;赶火车狂奔&#xff0c;找检票口找到怀疑人生…想查“最早到北京的车”&#xff1f;时刻表翻到眼瞎&#xff01;列车晚点&#xff1f;新出发时间算到脑壳疼&#xff01; 我们这次将…

UVA11990 ``Dynamic‘‘ Inversion

UVA11990 Dynamic Inversion题目链接题意输入格式输出格式分析CDQ分治嵌套&#xff08;树状数组套BST&#xff09;分块k-D Tree题目链接 UVA11990 Dynamic’’ Inversion 题意 给一个 1~n 的排列A&#xff0c;要求按照某种顺序删除一些数&#xff08;其他数顺序不变&#xff0…

银河麒麟“安装器”安装方法

书接上回&#xff1a;银河麒麟安装软件商店方法-CSDN博客 过了几天发现当时一不小心把系统自带的“安装器”软件也卸载掉了&#xff0c;导致现在deb文件只能通过命令行安装&#xff0c;寻思这可不行&#xff0c;就想一下应该怎么安装。 首先&#xff0c;为了确认一下安装器的…

计算机毕设分享-基于SpringBoot的健身房管理系统(开题报告+前后端源码+Lun文+开发文档+数据库设计文档)

基于SpringBoot的健身房管理系统分享一套完整的基于SpringBoot的健身房管理系统毕业设计&#xff08;开题报告完整前后端源码Lun文 开发文档数据库设计文档&#xff09;系统分为三个角色功能如下&#xff1a;用户功能需求描述管理员功能需求描述教练功能需求描述开题报告系统功…

代码审计与web安全选择题1

软件供应链安全的基础是&#xff08; &#xff09;A.完善的需求分析B.源代码安全C.渗透测试D.软件测试参考答案&#xff1a;B保证源代码安全的主要措施包括&#xff08; &#xff09;A.开发工具和环境的安全B.代码安全C.渗透测试D.代码审计E.软件的说明文档完整参考…

python基本数据类型 数据类型转换 数字 菜鸟教程笔记

python基本数据类型 数据类型转换 数字 菜鸟教程笔记 1.基本数据类型 Python 中的变量不需要声明。每个变量在使用前都必须赋值&#xff0c;变量赋值以后该变量才会被创建。 在 Python 中&#xff0c;变量就是变量&#xff0c;它没有类型&#xff0c;我们所说的"类型"…

USRP X410 X440 5G及未来通信技术的非地面网络(NTN)

概述 在本白皮书中&#xff0c;我们将介绍NTN的现状、正处于探索阶段的一些新应用&#xff0c;以及最重要的一点&#xff0c;我们需要克服哪些技术挑战才能让这个市场充满活力。最后&#xff0c;我们将概述为实现实用高效的测试&#xff0c;NI围绕NTN所做的努力&#xff0c;该测…

基于SpringBoot+Vue的电脑维修管理系统(WebSocket实时聊天、Echarts图形化分析)

“ &#x1f388;系统亮点&#xff1a;WebSocket实时聊天、Echarts图形化分析”01系统开发工具与环境搭建—前后端分离架构项目架构&#xff1a;B/S架构运行环境&#xff1a;win10/win11、jdk17小程序端&#xff1a;技术&#xff1a;Uniapp&#xff1b;UI库&#xff1a;colorUI…

2025.7.28总结

今天真有点小烦&#xff0c;工作有些不太顺利&#xff0c;我是真没想到&#xff0c;阻塞我工作开展得竟然是我的主管。当初需求澄清的时候&#xff0c;开发说要申请一个便携&#xff0c;我当时申请的时候也跟主管说了&#xff0c;需求测试的时候要使用到&#xff0c;但主管要我…

DBA常用数据库查询语句

1 数据库信息 1.1 数据库概要 select a.name "DB Name",e.global_name "Global Name",c.host_name "Host Name",c.instance_name "Instance Name" ,DECODE(c.logins,RESTRICTED,YES,NO) "Restricted Mode",a.log_mode &quo…

【c++深入系列】:万字详解priority_queue(附模拟实现的源码)

&#x1f525; 本文专栏&#xff1a;c &#x1f338;作者主页&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客励志语录&#xff1a; 真正的强大&#xff0c;不是从不跌倒&#xff0c;而是每次跌倒后都能笑着站起来 ★★★ 本文前置知识&#xff1a; 模版 引入 那么pri…

分享一个脚本,从mysql导出数据csv到hdfs临时目录

想从mysql导出一个表到csv文件&#xff0c;然后上传到hdfs&#xff0c;开始使用sqoop&#xff0c;结果各种问题频出&#xff1a; https://blog.csdn.net/weixin_45357522/article/details/149498030 https://blog.csdn.net/weixin_45357522/article/details/149449413 特别是那…

OpenLayers 综合案例-区域掩膜

看过的知识不等于学会。唯有用心总结、系统记录&#xff0c;并通过温故知新反复实践&#xff0c;才能真正掌握一二 作为一名摸爬滚打三年的前端开发&#xff0c;开源社区给了我饭碗&#xff0c;我也将所学的知识体系回馈给大家&#xff0c;助你少走弯路&#xff01; OpenLayers…