您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

架构师之路——模块类的设计与实现

时间:2023-10-20 14:17:54  来源:今日头条  作者:Red果果

在软件开发中,构建模块化、可扩展和易维护的应用程序是每位架构师的目标。本文将介绍如何设计和实现一个模块类来构建一个模块化编程框架,以便更好地管理和扩展应用程序功能。

引言

在软件开发中,模块化编程是一种重要的架构方法。它将应用程序分解为多个相互独立的模块,每个模块负责不同的任务。这种方法使得代码更易维护、更易扩展,也更易重用。本文将介绍一个简单而强大的模块化编程框架,它包括两个主要组件:模块类(Module)和模块工厂类(ModuleFactory)。这两者的结合为开发者提供了一种灵活的方式,可以轻松地创建和管理模块。

模块类(Module)

设计

模块类是模块化编程框架的核心。每个模块都是一个继承自 Module 的类。模块类有一个名字属性,用于唯一标识每个模块。

class Module {
public:
    Module() = default;
    virtual ~Module() = default;

    const std::string &getModuleName() const {
        return moduleName_;
    }

protected:
    void setModuleName(const std::string &name) {
        moduleName_ = name;
    }

private:
    std::string moduleName_;
    friend class ModuleFactory;
};

在上述代码中,Module 类包括了以下主要部分:

  • getModuleName(): 获取模块的名字。
  • setModuleName(const std::string &name): 设置模块的名字。

setModuleName 方法的私有访问权限确保只有 ModuleFactory 类能够修改模块的名字。

模块工厂类(ModuleFactory)

设计

模块工厂类是一个用于创建和管理模块的中心枢纽。每个模块必须在工厂中进行注册,以便能够通过工厂创建和获取模块的实例。

 class ModuleFactory {
private:
    // 内部结构体,用于标识模块
    struct moduleid {
        moduleid() = default;
        moduleid(std::string n, std::size_t h)
            : name(std::move(n)), code(h) {}
        explicit moduleid(const std::type_info &info)
            : name(info.name()), code(info.hash_code()) {}

        bool operator==(const moduleid &mid) const {
            return name == mid.name && code == mid.code;
        }

        std::string name;
        std::size_t code = 0;
    };

public:
    // 获取 ModuleFactory 的单例实例
    static ModuleFactory &getFactory() {
        static ModuleFactory factory;
        return factory;
    }

    // 获取注册在工厂中的模块名称集合
    const std::unordered_set<std::string> &getModuleNames() const {
        return *moduleNames_;
    }

    // 用于注册模块的辅助结构体
    template<typename T, typename C = T>
    struct ModuleRegisterHelper {
        // 构造函数,用于注册模块
        template<typename... Args>
        ModuleRegisterHelper(std::string n, Args &&...args) {
            auto mptr = getFactory().moduleMapTable_;
            if (mptr->find(n) != mptr->end()) {
                throw std::invalid_argument("模块 " + n + " 已经注册。");
            }
            getFactory().moduleNames_->insert(n);
            std::function<std::unique_ptr<Module>(Args...)> create_func = [](Args... args) {
                return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
            };
            const std::any const_any = std::any(create_func);
            (*mptr)[n] = std::make_pAIr(moduleid(typeid(C)), const_any);
        }
    };

    // 获取指定名称和类型的模块
    template<typename T = Module, typename... Args>
    typename std::enable_if<std::is_base_of<Module, T>::value, std::unique_ptr<T>>::type
    getModule(const std::string &n, Args &&...args) {
        auto mptr = getFactory().moduleMapTable_;
        auto miter = mptr->find(n);
        if (miter == mptr->end()) {
            throw std::runtime_error("找不到名称为 " + n + " 的模块。");
        }
        if (miter->second.first == moduleid(typeid(T))) {
            auto moduleCreator = std::any_cast<std::function<std::unique_ptr<Module>(Args...)>>(miter->second.second);
            std::unique_ptr<Module> module = moduleCreator(std::forward<Args>(args)...);
            module->setModuleName(n);
            return std::unique_ptr<T>(static_cast<T *>(module.release()));
        }
        auto moduleCreator = std::any_cast<std::function<std::unique_ptr<Module>(Args...)>>(miter->second.second);
        std::unique_ptr<Module> module = moduleCreator(std::forward<Args>(args)...);
        if (!dynamic_cast<T *>(module.get())) {
            throw std::runtime_error("无法将模块 " + n + " 产生的类型转换为 " + typeid(T).name());
        }
        module->setModuleName(n);
        return std::unique_ptr<T>(static_cast<T *>(module.release()));
    }

private:
    static std::unordered_map<std::string, std::pair<moduleid, std::any>> *moduleMapTable_;
    static std::unordered_set<std::string> *moduleNames_;

    ModuleFactory() {}
    ModuleFactory(const ModuleFactory &) = delete;
    ModuleFactory(ModuleFactory &&) = delete;
};

在 ModuleFactory 类中,可以创建、获取和管理已注册的模块。

注册模块

要使用模块工厂创建模块,需要首先注册模块。这里是通过
ModuleFactory::ModuleRegisterHelper 模板类来实现的。在注册模块时,需要提供模块的类型和名字。

可以使用又爱又恨的宏,避免了手动编写大量的注册代码:

#define MODULE_VARIABLE_NAME(module_name, module_type) Module_##module_name##_##module_type##_
#define REGISTER_MODULE(module_name, module_type, ...) 
    static module::ModuleFactory::ModuleRegisterHelper<module_type> MODULE_VARIABLE_NAME(module_name, module_type)(#module_name, ##__VA_ARGS__)
#define DECLARE_MODULE(module_type, ...) REGISTER_MODULE(module_type, module_type, ##__VA_ARGS__)

解释如下:

  1. MODULE_VARIABLE_NAME(module_name, module_type) 宏:
  2. 该宏用于生成一个唯一的变量名称,通常用于防止冲突。它的作用是在模块名称和模块类型之间创建一个唯一的标识符。
  3. module_name:模块名称,通常是一个字符串。
  4. module_type:模块类型,通常是一个C++类的类型。
  5. 例如,如果你有一个模块名称为 "MyModule",模块类型为 "MyModuleType",则调用 MODULE_VARIABLE_NAME 宏后将生成 Module_MyModule_MyModuleType_ 作为标识符。
  6. REGISTER_MODULE(module_name, module_type, ...) 宏:
  7. 该宏用于注册模块并将其添加到工厂中,以便后续可以根据名称获取该模块。
  8. module_name:模块的名称,通常是一个字符串。
  9. module_type:模块的类型,通常是一个C++类的类型。
  10. ...:可选的额外参数,用于创建模块对象。
  11. 该宏的作用是创建一个静态变量,并使用 MODULE_VARIABLE_NAME 宏生成唯一的变量名称,然后通过 ModuleFactory::ModuleRegisterHelper 类将模块注册到工厂中。这样,你可以在工厂中使用模块名称和类型来创建模块对象。
  12. 例如,如果你调用 REGISTER_MODULE("MyModule", MyModuleType, arg1, arg2),宏将创建一个静态变量 Module_MyModule_MyModuleType_ 并使用 ModuleFactory::ModuleRegisterHelper 来注册一个名为 "MyModule" 类型为 "MyModuleType" 的模块,同时传递额外的参数 arg1 和 arg2 用于创建该模块对象。
  13. 可以很方便的注册模块:
REGISTER_MODULE( "MyModule",MyModule);

不喜欢使用宏则可以:

template<typename T, typename... Args>
void registerModule(const std::string &moduleName, Args &&...args) {
    static ModuleFactory::ModuleRegisterHelper<T> helper(moduleName, std::forward<Args>(args)...);
}

注册模块:

registerModule<MyModuleType>("MyModule", arg1, arg2);

使用模块

下面是一个示例,展示如何使用模块类和模块工厂类来创建和管理模块。

// 定义一个模块类
class MyModule : public Module {
public:
    // 自定义模块的行为
};

// 注册模块
REGISTER_MODULE( "MyModule",MyModule);

int main() {
    // 使用模块工厂创建模块
    ModuleFactory &factory = ModuleFactory::getFactory();
    MyModule *module = factory.getMultiModule<MyModule>("MyModule");

    // 使用模块
    if (module) {
        std::cout << "Created module: " << module->getModuleName() << std::endl;
    }

    return 0;
}

项目使用案例:

下面以虚拟商城系统为例,演示如何使用模块类和模块工厂类来创建虚拟商城系统,包括购物车管理、用户注册和商品管理等多个模块。

首先,创建购物车管理模块:

#include "Module.h"

class ShoppingCartModule : public module::Module {
public:
    ShoppingCartModule() {
        setModuleName("ShoppingCartModule");
    }

    void execute() override {
        std::cout << "Shopping Cart Management Module executed." << std::endl;
        // 添加购物车操作
        addToCart("Product1", 10.0);
        addToCart("Product2", 15.0);
        displayCartContents();
        calculateTotal();
    }

    void addToCart(const std::string& item, double price) {
        cart.push_back(std::make_pair(item, price));
        std::cout << "Added " << item << " to the cart. Price: " << price << " USD" << std::endl;
    }

    void displayCartContents() {
        std::cout << "Cart Contents:" << std::endl;
        for (const auto& item : cart) {
            std::cout << item.first << " - " << item.second << " USD" << std::endl;
        }
    }

    void calculateTotal() {
        double total = 0.0;
        for (const auto& item : cart) {
            total += item.second;
        }
        std::cout << "Total Cart Value: " << total << " USD" << std::endl;
    }

private:
    std::vector<std::pair<std::string, double>> cart;
};

DECLARE_MODULE(ShoppingCartModule);

然后,创建用户注册模块:

#include "Module.h"

class UserRegistrationModule : public module::Module {
public:
    UserRegistrationModule() {
        setModuleName("UserRegistrationModule");
    }

    void execute() override {
        std::cout << "User Registration Module executed." << std::endl;
        // 用户注册操作
        registerUser("User1");
        registerUser("User2");
        displayRegisteredUsers();
        loginUser("User1");
    }

    void registerUser(const std::string& username) {
        users.push_back(username);
        std::cout << "Registered new user: " << username << std::endl;
    }

    void displayRegisteredUsers() {
        std::cout << "Registered Users:" << std::endl;
        for (const std::string& user : users) {
            std::cout << user << std::endl;
        }
    }

    void loginUser(const std::string& username) {
        std::cout << "User " << username << " logged in." << std::endl;
    }

private:
    std::vector<std::string> users;
};

DECLARE_MODULE(UserRegistrationModule);

最后,创建商品管理模块:

#include "Module.h"

class ProductManagementModule : public module::Module {
public:
    ProductManagementModule() {
        setModuleName("ProductManagementModule");
    }

    void execute() override {
        std::cout << "Product Management Module executed." << std::endl;
        // 商品管理操作
        addProduct("Product1", 10.0, 20);
        addProduct("Product2", 15.0, 15);
        displayProducts();
        showProductDetails("Product1");
    }

    void addProduct(const std::string& product, double price, int quantity) {
        products.push_back(std::make_pair(product, std::make_pair(price, quantity));
        std::cout << "Added new product: " << product << " Price: " << price << " USD Quantity: " << quantity << std::endl;
    }

    void displayProducts() {
        std::cout << "Available Products:" << std::endl;
        for (const auto& product : products) {
            std::cout << product.first << " - Price: " << product.second.first << " USD Quantity: " << product.second.second << std::endl;
        }
    }

    void showProductDetails(const std::string& product) {
        for (const auto& p : products) {
            if (p.first == product) {
                std::cout << "Product Details - " << product << ":" << std::endl;
                std::cout << "Price: " << p.second.first << " USD" << std::endl;
                std::cout << "Available Quantity: " << p.second.second << std::endl;
                return;
            }
        }
        std::cout << "Product not found: " << product << std::endl;
    }

private:
    std::vector<std::pair<std::string, std::pair<double, int>> products;
};

DECLARE_MODULE(ProductManagementModule);

最终的main函数会非常简洁:

#include "Module.h"

int main() {
    // 获取模块工厂实例
    module::ModuleFactory& factory = module::ModuleFactory::getFactory();

    // 获取购物车管理模块并执行
   auto shoppingCartModule = factory.getMultiModule<ShoppingCartModule>("ShoppingCartModule");
    shoppingCartModule->execute();

    // 获取用户注册模块并执行
    auto  userRegistrationModule = factory.getMultiModule<UserRegistrationModule>("UserRegistrationModule");
    userRegistrationModule->execute();

    // 获取商品管理模块并执行
   auto  productManagementModule = factory.getMultiModule<ProductManagementModule>("ProductManagementModule");
    productManagementModule->execute();
    return 0;
}

结论

模块化编程是一种强大的架构方法,它使得应用程序更容易维护、扩展和重用。通过使用模块类和模块工厂类,能够更好地管理和扩展应用程序的功能。模块化编程框架不仅可以帮助架构师构建可扩展的应用程序,还可以帮助开发者编写更具模块性的代码,提高代码质量和可维护性。

本文虽然简单,但一个大型框架同样也是由一招一式构成,大道至简,藏拙于巧。

参考

参考文献: [1] Gamma, E., Helm, R., Johnson, R., & Vlissides, J. (1994). Design patterns: elements of reusable object-oriented software. Pearson Education.

[2] Martin, R. C. (2003). Agile software development, principles, patterns, and practices. Pearson Education.

[3] Fowler, M. (2018). Refactoring: improving the design of existing code. Addison-Wesley Professional.



Tags:架构   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  Search: 架构  点击:(4)  评论:(0)  加入收藏
大模型应用的 10 种架构模式
作者 | 曹洪伟在塑造新领域的过程中,我们往往依赖于一些经过实践验证的策略、方法和模式。这种观念对于软件工程领域的专业人士来说,已经司空见惯,设计模式已成为程序员们的重...【详细内容】
2024-03-27  Search: 架构  点击:(13)  评论:(0)  加入收藏
哈啰云原生架构落地实践
一、弹性伸缩技术实践1.全网容器化后一线研发的使用问题全网容器化后一线研发会面临一系列使用问题,包括时机、容量、效率和成本问题,弹性伸缩是云原生容器化后的必然技术选择...【详细内容】
2024-03-27  Search: 架构  点击:(10)  评论:(0)  加入收藏
京东小程序数据中心架构设计与最佳实践
一、京东小程序是什么京东小程序平台能够提供开放、安全的产品,成为品牌开发者链接京东内部核心产品的桥梁,致力于服务每一个信任我们的外部开发者,为不同开发能力的品牌商家提...【详细内容】
2024-03-27  Search: 架构  点击:(9)  评论:(0)  加入收藏
从 MySQL 到 ByteHouse,抖音精准推荐存储架构重构解读
ByteHouse是一款OLAP引擎,具备查询效率高的特点,在硬件需求上相对较低,且具有良好的水平扩展性,如果数据量进一步增长,可以通过增加服务器数量来提升处理能力。本文将从兴趣圈层...【详细内容】
2024-03-22  Search: 架构  点击:(23)  评论:(0)  加入收藏
全程回顾黄仁勋GTC演讲:Blackwell架构B200芯片登场
北京时间3月19日4时-6时,英伟达创始人黄仁勋在美国加州圣何塞SAP中心登台,发表GTC 2024的主题演讲《见证AI的变革时刻》。鉴于过去一年多时间里AI带来的生产力变革,以及英伟达...【详细内容】
2024-03-19  Search: 架构  点击:(17)  评论:(0)  加入收藏
高并发架构设计(三大利器:缓存、限流和降级)
软件系统有三个追求:高性能、高并发、高可用,俗称三高。本篇讨论高并发,从高并发是什么到高并发应对的策略、缓存、限流、降级等。引言1.高并发背景互联网行业迅速发展,用户量剧...【详细内容】
2024-03-13  Search: 架构  点击:(5)  评论:(0)  加入收藏
有了LLM,所有程序员都将转变为架构师?
编译 | 言征 出品 | 51CTO技术栈(微信号:blog51cto)生成式人工智能是否会取代人类程序员?可能不会。但使用生成式人工智能的人类可能会,可惜的是,现在还不是时候。目前,我们正在见...【详细内容】
2024-03-07  Search: 架构  点击:(19)  评论:(0)  加入收藏
如何判断架构设计的优劣?
架构设计的基本准则是非常重要的,它们指导着我们如何构建可靠、可维护、可测试的系统。下面是这些准则的转换表达方式:简单即美(KISS):KISS原则的核心思想是保持简单。在设计系统...【详细内容】
2024-02-20  Search: 架构  点击:(36)  评论:(0)  加入收藏
通用数据湖仓一体架构正当时
这篇博文中提出的建议并不新鲜。事实上许多组织已经投入了数年时间和昂贵的数据工程团队的工作,以慢慢构建这种架构的某个版本。我知道这一点,因为我以前在Uber和LinkedIn做过...【详细内容】
2024-01-15  Search: 架构  点击:(75)  评论:(0)  加入收藏
▌简易百科推荐
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  步步运维步步坑    Tags:架构   点击:(4)  评论:(0)  加入收藏
大模型应用的 10 种架构模式
作者 | 曹洪伟在塑造新领域的过程中,我们往往依赖于一些经过实践验证的策略、方法和模式。这种观念对于软件工程领域的专业人士来说,已经司空见惯,设计模式已成为程序员们的重...【详细内容】
2024-03-27    InfoQ  Tags:架构模式   点击:(13)  评论:(0)  加入收藏
哈啰云原生架构落地实践
一、弹性伸缩技术实践1.全网容器化后一线研发的使用问题全网容器化后一线研发会面临一系列使用问题,包括时机、容量、效率和成本问题,弹性伸缩是云原生容器化后的必然技术选择...【详细内容】
2024-03-27  哈啰技术  微信公众号  Tags:架构   点击:(10)  评论:(0)  加入收藏
DDD 与 CQRS 才是黄金组合
在日常工作中,你是否也遇到过下面几种情况: 使用一个已有接口进行业务开发,上线后出现严重的性能问题,被老板当众质疑:“你为什么不使用缓存接口,这个接口全部走数据库,这怎么能扛...【详细内容】
2024-03-27  dbaplus社群    Tags:DDD   点击:(11)  评论:(0)  加入收藏
高并发架构设计(三大利器:缓存、限流和降级)
软件系统有三个追求:高性能、高并发、高可用,俗称三高。本篇讨论高并发,从高并发是什么到高并发应对的策略、缓存、限流、降级等。引言1.高并发背景互联网行业迅速发展,用户量剧...【详细内容】
2024-03-13    阿里云开发者  Tags:高并发   点击:(5)  评论:(0)  加入收藏
如何判断架构设计的优劣?
架构设计的基本准则是非常重要的,它们指导着我们如何构建可靠、可维护、可测试的系统。下面是这些准则的转换表达方式:简单即美(KISS):KISS原则的核心思想是保持简单。在设计系统...【详细内容】
2024-02-20  二进制跳动  微信公众号  Tags:架构设计   点击:(36)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  ijunfu  今日头条  Tags:SpringBoot   点击:(8)  评论:(0)  加入收藏
PHP+Go 开发仿简书,实战高并发高可用微服务架构
来百度APP畅享高清图片//下栽のke:chaoxingit.com/2105/PHP和Go语言结合,可以开发出高效且稳定的仿简书应用。在实现高并发和高可用微服务架构时,我们可以采用一些关键技术。首...【详细内容】
2024-01-14  547蓝色星球    Tags:架构   点击:(114)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11    王建立  Tags:Spring Boot   点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  互联网架构小马哥    Tags:Spring Boot   点击:(115)  评论:(0)  加入收藏
站内最新
站内热门
站内头条