前言
对于世界而言,你是一个人;但是对于某个人,你是她的整个世界。
-- 《水晶之恋》
❝享元模式是一种结构型设计模式, 它允许你在消耗少量内存的情况下支持大量对象。 ❞
简单的理解: 一个类的成员非常多,创建此对象很消耗资源,在实际场景中又需要反复创建和销毁该对象。所消耗的内存,就更加庞大。
如果此时设计一个对象池,里面缓存一定的对象,软件在用时申请,不用时回收。就能实现对象的重复利用,而多次创建和销毁对象。
从上述的解释可以总结出,享元模式主要在资源有限的情况下,对创建大量对象行为的一种约束。通过初始化已有的对象,达到与创建对象一样的效果。
当前开发板仅存在3个Led灯,其中一个被用作Power指示灯,另两个可被用作软件调试或功能灯,设计Led资源管理,避免使用Led时发生冲突。(消耗的内存不方便演示,此处用Led资源的消耗模拟内存消耗)
板子Led资源有限,其中一个又被指定为Power灯不可被占用,那么仅剩两个Led可被使用。软件上可分为UnShare Led 和 Share Led,其中假设两个Shared Led分别为Led 1和Led2。
如果不对Led资源进行管理,可能会出现如下情况:
因为Led的操作都是一样的,只是具体资源有差异。可引用享元模式根据现有Led资源创建若干个Led对象放入对象工厂,各个模块从对象工厂申请即可使用。
根据上述分析结合享元模式构建类图:
「编程环境」
「工程结构」
Flyweight/
├── led.cc
├── led_factory.cc
├── led_factory.h
├── led.h
├── main.cc
└── Makefile
「Led通用功能接口」
class CLed
{
public:
CLed () {}
virtual ~CLed() {}
void SetStatus(ELedStatus status);
ELedStatus GetStatus();
void SetUsedMode(EUsedMode mode);
EUsedMode GetUsedMode();
void SetPermission(EPermission permission);
EPermission GetPermission();
void SetFrequency(int freq);
void SetIndex(int value);
void UpdateLed(EPermission permission, EUsedMode mode, int freq);
virtual void Start();
virtual void Stop();
virtual void Relase();
private:
int mIndex;
int mFreq;
ELedStatus mStatus;
EUsedMode mUsedMode;
EPermission mPermission;
};
此类主要实现Led的通用功能,不涉及具体的Led管脚等硬件信息。
「Led管理工厂接口」
class CLedFactory
{
public:
static CLedFactory* GetInstance();
CLed* GetLed(EPermission permission, EUsedMode mode = LED_MODE_DEFAULT, int freq = 10);
private:
std::map<int, CLed *> mLedTable;///Led享元对象
CLedFactory() {} ///< 单例模式
~CLedFactory() {}
};
此类主要用于缓存Led对象,目前仅缓存三个对象: Unshare Led、Share Led(Led1、Led2)。客户端通过GetLed接口获取未被使用的Led资源。
「工厂获取Led接口实现」
CLed* CLedFactory::GetLed(EPermission permission, EUsedMode mode, int freq)
{
int i, sum = 0, location = -1;
switch (permission)
{
case LED_UNSHARED:
{
// 返回Power Led对象
if (CUnsharedLed::GetInstance()->GetStatus() == LED_IDLE) {
CUnsharedLed::GetInstance()->SetStatus(LED_BUSY);
return CUnsharedLed::GetInstance();
} else {
return NULL;
}
}
break;
case LED_SHARED:
{
sum = mLedTable.size();
// loop: 遍历所有LED状态,返回空闲的LED
for (i = 0; i < sum; i++) {
if ( mLedTable[i]->GetStatus() == LED_IDLE)
{
location = i;
goto RET; // 找到空闲的LED, 返回当前下标
}
}
// 当前存在的LED对象都处于busy状态,
// 若Led资源未到上限,则创建新的Led对象。
if (i == sum && sum < MAX_SHARED_LED) {
FACTORY_LOGD("Create Shared Led %d!\n", i);
mLedTable.insert(std::pair<int, CLed*>(i, new CSharedLed()));
location = i;
}
}
break;
default:
break;
}
RET:
if (location >= 0) {
mLedTable[location]->UpdateLed(permission, mode, freq);
return mLedTable[location];
} else {
return NULL;
}
}
「客户端代码」
int main(int argc, char *argv[])
{
CLedFactory *theLedFactory = CLedFactory::GetInstance();
if (!theLedFactory) {
MAIN_LOGE("Get Led Factory failed!\n");
return -1;
}
// ------------------- UnShare Led Test ------------------------
MAIN_LOG("-> UnShare led test 1st!\n");
CLed *thePowerLed1 = theLedFactory->GetLed(LED_UNSHARED);
if (thePowerLed1) {
thePowerLed1->Start();
} else {
MAIN_LOGE("Get Power Led failed!\n");
}
thePowerLed1->Relase(); // 当前使用释放,才可被再次使用
MAIN_LOG("\n-> UnShare led test 2nd!\n");
CLed *thePowerLed2 = theLedFactory->GetLed(LED_UNSHARED);
if (thePowerLed2) {
thePowerLed2->Start();
} else {
MAIN_LOGE("Get Power Led failed!\n");
}
// ------------------- Test End ------------------------
// ------------------- Share Led Test ------------------------
MAIN_LOG("\n-> Share led test 1st!\n");
CLed *theLed1 = theLedFactory->GetLed(LED_SHARED, LED_MODE_HORSE);
if (theLed1) {
theLed1->Start();
} else {
MAIN_LOGE("Get Led failed!\n");
}
MAIN_LOG("\n-> Share led test 2nd!\n");
CLed *theLed2 = theLedFactory->GetLed(LED_SHARED, LED_MODE_BREATH);
if (theLed2) {
theLed2->Start();
} else {
MAIN_LOGE("Get Led failed!\n");
}
// Share Led 仅有两个,若不释放占用的Led。Led3就拿不到资源
MAIN_LOG("\n-> Share led test 3rd!\n");
CLed *theLed3 = theLedFactory->GetLed(LED_SHARED, LED_MODE_BREATH);
if (theLed3) {
theLed3->Start();
} else {
MAIN_LOGE("Get Led failed!\n");
}
// ------------------- Test End ------------------------
return 0;
}
$ ./exe
-> UnShare led test 1st!
Power Led (pin10) ON.
Power Led (pin10) OFF.
Relase power Led (pin10).
-> UnShare led test 2nd!
Power Led (pin10) ON.
-> Share led test 1st!
Led 0 (pin20) Start. Mode: Horse Mode
-> Share led test 2nd!
Led 1 (pin21) Start. Mode: Breath Mode
-> Share led test 3rd!
74 Main E: Get Led failed!
用心感悟,认真记录,写好每一篇文章,分享每一框干货。
更多文章内容包括但不限于C/C++、Linux、开发常用神器等,可进入“开源519”公众号聊天界面输入“文章目录”, 或菜单栏选择“文章目录”查看所有文章。后台聊天输入本文标题,可查看源码。