以下为学习时对各种设计模式的简单理解,还没有深入学习和实际应用,推荐1个 很棒的网站学习设计模式,每个模式都有遇到的痛点和解决的方法,还有2~3个应用场景,各种语言的代码示例,简明准确的UML类图,精美可爱的配图,推荐大家去看。
创建类型
单例模式
饿汉
构建时就创建
懒汉
- 单线程-访问到的时候才创建
- 多线程-低效率
做法:加锁->若未创建则创建->获取资源->解锁
缺点:效率低,每次访问之前都要加锁,资源创建之后不能被同时被多个线程访问 - 多线程-双重判断
做法:判断资源未存在->加锁->二次判断资源未存在->创建资源->解锁->获取资源
原因:先判断资源是否存在,只有第1次判断到资源不存在才需要加锁,当资源创建之后就不用再加锁了,多线程在大部分情况下可同时访问,提高资源访问效率;在加锁之后需要再次判断资源是否存在,可能在第1次判断和拿到锁的时间间隙中资源已经被其他线程访问和创建了,因此需要二次判断。
openbmc项目实际应用
在bmcweb/include/sessions.hpp中,有1个类用来管理web session的类SessionStore
。其创建方式就是单例模式,且是第一次使用到这个对象才会创建这个对象:
class SessionStore
{
public:
static SessionStore& getInstance()
{
static SessionStore sessionStore;
return sessionStore;
}
...
};
其他类需要用到此类方法时,都需通过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);
项目中为什么使用单例模式呢?
- 作为全局管理对象:
SessionStore
作为管理类,起到的是全局统领的作用,只需要1个对象就够了,多个对象反而使管理变得混乱 - 节约资源:
SessionStore
中保存着所有web session的信息,若可创建多个对象,则会引起相同web session拷贝,session发生变化还要使用一些同步机制保证不同SessionStore
对象的同步。 - 统一文件的访问:在关闭BMC前可能连接着一些web session,关闭前需要将这些数据保存到起来,重启后要重新获取,单例保证只有1个对象对文件进行读写,避免重复读写。
工厂方法
当多种产品都继承于同1个基类,如美的空调和海尔空调都继承空调类,则可使用工厂方法。让多个工厂类继承于同1个工厂基类,对应去生产不同产品。
简单工厂方法
参考链接
多种产品继承同1个基类,可创建1个工厂类,根据不同的参数,以调用不同产品类的构造函数,来创建出不同的产品
openbmc项目实际应用
phosphor-pid-control是风扇控制模块,根据当前温度传感器/风扇转速/调速参数,使用PID算法来设置风扇目标转速。此模块中的主要类图如下:
-
Controller
:控制器,为纯虚类,作用是通过inputProc
获取输入值,通过process
和获得的输入值以计算输出值,通过outputProc
让输出值起作用。 -
PIDController
:PID控制器,将输入值和目标值作为PID算法的参数,以获取输出值。 -
StepwiseController
:简单的温度控制器,维护1个阶梯式的温度-转速的表格,每个温度范围对应1个目标转速。输入值为多个传感器温度的最大值,输出值为最大温度对应的目标转速,会将目标转速交给FanController
处理。 -
ThermalController
:温度控制器,采用PID算法,将所有温度传感器获得的最大温度作为输入值,但不设目标值,根据PID算法计算最终的目标转速,会将目标转速交给FanController
处理。 -
FanController
:风扇控制器,采用PID算法,将所有温度控制器获得的目标转速的最大值作为目标值,将风扇当前值作为输入值,根据PID算法计算最终的目标转速,并将此值写入风扇背板的CPLD寄存器中,最终控制风扇转速。 -
zone
:将物理区域抽象成1个类,每个区域都有一至多个硬件温度传感器和风扇,一至多个虚拟温度控制器和风扇控制,控制风扇转速以确保每个区域的硬件在适宜温度内。
在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));
...
}
}
}
创建具体控制器对象方法的createXXXController
其实是每个控制器类的静态成员函数。文章来源:https://www.toymoban.com/news/detail-701330.html
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;
}
为什么这个场景像简单工厂模式:文章来源地址https://www.toymoban.com/news/detail-701330.html
- 系统耦合度较低:用户想创建控制器对象时,只需要根据规范,在json文件中配置控制器的属性如下:
type
为"fan"
则会创建1个风扇控制器,不用关注任何代码层面的细节,而且所有控制器。根本就不是了啦!
"pids": [
{
"name": "fan1-5",
"type": "fan",
"inputs": ["fan1", "fan5"],
"setpoint": 90.0,
}
]
抽象工厂
到了这里,关于设计模式概念学习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!