• 设计模式概念学习



    以下为学习时对各种设计模式的简单理解,还没有深入学习和实际应用,推荐1个 很棒的网站学习设计模式,每个模式都有遇到的痛点和解决的方法,还有2~3个应用场景,各种语言的代码示例,简明准确的UML类图,精美可爱的配图,推荐大家去看。

    创建类型

    单例模式

    饿汉

    构建时就创建

    懒汉

    1. 单线程-访问到的时候才创建
    2. 多线程-低效率
      做法:加锁->若未创建则创建->获取资源->解锁
      缺点:效率低,每次访问之前都要加锁,资源创建之后不能被同时被多个线程访问
    3. 多线程-双重判断
      做法:判断资源未存在->加锁->二次判断资源未存在->创建资源->解锁->获取资源
      原因:先判断资源是否存在,只有第1次判断到资源不存在才需要加锁,当资源创建之后就不用再加锁了,多线程在大部分情况下可同时访问,提高资源访问效率;在加锁之后需要再次判断资源是否存在,可能在第1次判断和拿到锁的时间间隙中资源已经被其他线程访问和创建了,因此需要二次判断。
    openbmc项目实际应用

    在bmcweb/include/sessions.hpp中,有1个类用来管理web session的类SessionStore。其创建方式就是单例模式,且是第一次使用到这个对象才会创建这个对象:

    class SessionStore
    {
      public:
        static SessionStore& getInstance()
        {
            static SessionStore sessionStore;
            return sessionStore;
        }
        ...
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    其他类需要用到此类方法时,都需通过getInstance()方法来获得SessionStore类唯一的对象sessionStore,如有1个用户登录web之后,需要新增1个web session,则需要通过getInstance()方法,将新的web session的信息保留在SessionStore唯一的对象中:

        // User is authenticated - create session
        std::shared_ptr<persistent_data::UserSession> session =
            persistent_data::SessionStore::getInstance().generateUserSession(
                username, req.ipAddress, clientId,
                persistent_data::PersistenceType::TIMEOUT, isConfigureSelfOnly);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    项目中为什么使用单例模式呢?

    1. 作为全局管理对象:SessionStore作为管理类,起到的是全局统领的作用,只需要1个对象就够了,多个对象反而使管理变得混乱
    2. 节约资源:SessionStore中保存着所有web session的信息,若可创建多个对象,则会引起相同web session拷贝,session发生变化还要使用一些同步机制保证不同SessionStore对象的同步。
    3. 统一文件的访问:在关闭BMC前可能连接着一些web session,关闭前需要将这些数据保存到起来,重启后要重新获取,单例保证只有1个对象对文件进行读写,避免重复读写。

    工厂方法

    当多种产品都继承于同1个基类,如美的空调和海尔空调都继承空调类,则可使用工厂方法。让多个工厂类继承于同1个工厂基类,对应去生产不同产品。

    简单工厂方法

    参考链接
    多种产品继承同1个基类,可创建1个工厂类,根据不同的参数,以调用不同产品类的构造函数,来创建出不同的产品

    openbmc项目实际应用

    phosphor-pid-control是风扇控制模块,根据当前温度传感器/风扇转速/调速参数,使用PID算法来设置风扇目标转速。此模块中的主要类图如下:

    1. Controller:控制器,为纯虚类,作用是通过inputProc获取输入值,通过process和获得的输入值以计算输出值,通过outputProc让输出值起作用。
    2. PIDController:PID控制器,将输入值和目标值作为PID算法的参数,以获取输出值。
    3. StepwiseController:简单的温度控制器,维护1个阶梯式的温度-转速的表格,每个温度范围对应1个目标转速。输入值为多个传感器温度的最大值,输出值为最大温度对应的目标转速,会将目标转速交给FanController处理。
    4. ThermalController:温度控制器,采用PID算法,将所有温度传感器获得的最大温度作为输入值,但不设目标值,根据PID算法计算最终的目标转速,会将目标转速交给FanController处理。
    5. FanController:风扇控制器,采用PID算法,将所有温度控制器获得的目标转速的最大值作为目标值,将风扇当前值作为输入值,根据PID算法计算最终的目标转速,并将此值写入风扇背板的CPLD寄存器中,最终控制风扇转速。
    6. zone:将物理区域抽象成1个类,每个区域都有一至多个硬件温度传感器和风扇,一至多个虚拟温度控制器和风扇控制,控制风扇转速以确保每个区域的硬件在适宜温度内。
    Controller
    +inputProc() : double
    +outputProc(value)
    +process()
    ThermalController
    +createThermalPid(...) : ThermalController
    StepwiseController
    +createStepwiseController(...) : StepwiseController
    FanController
    +createFanPid(...) : FanController
    PIDController
    +setptProc() : double
    Zone
    -Controller[] _fans
    -Controller[] _thermals
    +addFanPID()
    +addThermalPID()

    在phosphor-pid-control/pid/builder.cpp中的buildZones函数,用来创建zone对象,根据json文件中的控制器类型的配置值来决定创建的控制器类型。创建zone的函数其实就可以视为1个简单工厂,创建控制器对象时,获取的参数均是用户在json文件中的配置。

    std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>>
        buildZones(...)
    {
    		...
            // For each PID create a Controller and a Sensor.
            for (const auto& [name, info] : pidConfig)
            {
            	...
                if (info.type == "fan")
                {
                	...
                    auto pid = FanController::createFanPid(zone.get(), name, inputs,
                                                           info.pidInfo);
    				zone->addFanPID(std::move(pid));
                	...
                }
                else if (isThermalType(info.type))
                {
                	...
                    auto pid = ThermalController::createThermalPid(
                        zone.get(), name, inputs, info.setpoint, info.pidInfo,
                        getThermalType(info.type));
                    zone->addThermalPID(std::move(pid));
                	...
                }
                else if (info.type == "stepwise")
                {
                	...
                    auto stepwise = StepwiseController::createStepwiseController(
                        zone.get(), name, inputs, info.stepwiseInfo);
                    zone->addThermalPID(std::move(stepwise));
                   ...
                }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    创建具体控制器对象方法的createXXXController其实是每个控制器类的静态成员函数。

    static std::unique_ptr<Controller> StepwiseController::createStepwiseController(
        ZoneInterface* owner, const std::string& id,
        const std::vector<std::string>& inputs, const ec::StepwiseInfo& initial)
    {
        // StepwiseController requires at least 1 input
        if (inputs.empty())
        {
            throw ControllerBuildException("Stepwise controller missing inputs");
        }
    
        auto thermal = std::make_unique<StepwiseController>(id, inputs, owner);
        thermal->setStepwiseInfo(initial);
    
        return thermal;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    为什么这个场景像简单工厂模式:

    1. 系统耦合度较低:用户想创建控制器对象时,只需要根据规范,在json文件中配置控制器的属性如下:type"fan"则会创建1个风扇控制器,不用关注任何代码层面的细节,而且所有控制器。根本就不是了啦!
    "pids": [
        {
            "name": "fan1-5",
            "type": "fan",
            "inputs": ["fan1", "fan5"],
            "setpoint": 90.0,
        }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    抽象工厂

  • 相关阅读:
    喷码机如何与封箱机配合?
    音量调节堆栈
    springboot基于web的在线问答社区系统设计与实现毕业设计源码061628
    C/C++语言100题练习计划 79——整数奇偶数排序(sort函数实现)
    RabbitMQ系列【14】备份交换机
    使用Echarts.js绘制多条折线图
    安装多个MySQL版本时如何连接到不同的数据库
    算力网络调研笔记
    探索AI搜索:天工AI,让信息获取更简单
    Vue 怎么调用ElementUI中的方法?
  • 原文地址:https://blog.csdn.net/m0_51531927/article/details/132679869