当前位置:网站首页>享元模式(Flyweight)
享元模式(Flyweight)
2022-06-26 12:40:00 【baboon_chen】
参考:
一、什么是享元模式?
定义:通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象。
需要将类的数据成员拆分成两个部分:内在状态、外在状态。内在是固定不变的,外在是可调整的数据。对于不变的内在信息,可以按共享的方式存储,从而减少内存占用。
比如,围棋和五子棋中的黑白棋子,棋盘中棋子的落点是变化的,颜色是可固定的。所以棋子只需要存储两份:黑子、白子。而落点可以存储在二维矩阵中。交警系统中对车辆信息的登记,可以将车辆信息划分为内在状态(品牌、型号、颜色)、外在状态(属主、车牌)。

二、示例
享元(Flyweight)模式包含以下主要角色:
- 抽象享元(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
- 具体享元(Concrete Flyweight):实现抽象享元角色中所规定的接口。
- 非享元(Unsharable Flyweight) :是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
- 享元工厂(Flyweight Factory):负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
- 客户角色通过享元工厂获取具体享元,并访问具体享元的相关方法。

1、车辆管理系统(车辆信息登记)
/**
* Flyweight Design Pattern
*
* 通过在多个对象之间共享状态的公共部分,而不是将所有数据保存在每个对象中,允许您将更多对象放入可用的RAM中。
* 示例表示一个公安汽车管理系统,每辆汽车的共享信息有(品牌、型号、颜色),非共享信息有(属主、车牌)。
*/
#include <iostream>
#include <string>
#include <unordered_map>
// 共享状态(内部状态)
struct SharedState
{
std::string brand_; // 品牌
std::string model_; // 型号
std::string color_; // 颜色
SharedState(const std::string &brand, const std::string &model, const std::string &color)
: brand_(brand), model_(model), color_(color)
{
}
friend std::ostream &operator<<(std::ostream &os, const SharedState &ss)
{
return os << "[ " << ss.brand_ << " , " << ss.model_ << " , " << ss.color_ << " ]";
}
};
// 非共享状态(外部状态)
struct UniqueState
{
std::string owner_; // 属主
std::string plates_; // 车牌
UniqueState(const std::string &owner, const std::string &plates)
: owner_(owner), plates_(plates)
{
}
friend std::ostream &operator<<(std::ostream &os, const UniqueState &us)
{
return os << "[ " << us.owner_ << " , " << us.plates_ << " ]";
}
};
/**
* 享元(Flyweight)类包含原始对象中共享的状态。
* 同一享元对象可在许多不同情景中使用。
* 享元中存储的状态被称为“内部状态”。传递给享元方法的状态被称为“外在状态”。
*/
class Flyweight
{
private:
SharedState *shared_state_;
public:
Flyweight(const SharedState *shared_state) : shared_state_(new SharedState(*shared_state))
{
}
Flyweight(const Flyweight &other) : shared_state_(new SharedState(*other.shared_state_))
{
}
~Flyweight()
{
delete shared_state_;
}
SharedState *shared_state() const
{
return shared_state_;
}
void Operation(const UniqueState &unique_state) const
{
std::cout << "Flyweight: Displaying shared (" << *shared_state_ << ") and unique (" << unique_state << ") state.\n";
}
};
/**
* 享元工厂(Flyweight Factory)会对已有享元的缓存池进行管理。
* 有了工厂后,客户端就无需直接创建享元,它们只需调用工厂并向其传递目标享元的一些内在状态即可。
* 工厂会根据参数在之前已创建的享元中进行查找,如果找到满足条件的享元就将其返回,如果没有找到就根据参数新建享元。
*/
class FlyweightFactory
{
private:
// 无序map容器不需要排序,hash查找。
std::unordered_map<std::string, Flyweight> flyweights_;
std::string GetKey(const SharedState &ss) const
{
return ss.brand_ + "_" + ss.model_ + "_" + ss.color_;
}
public:
FlyweightFactory(std::initializer_list<SharedState> share_states)
{
for (const SharedState &ss : share_states)
{
this->flyweights_.insert(std::make_pair<std::string, Flyweight>(this->GetKey(ss), Flyweight(&ss)));
}
}
// 没有就创建享元,有就复用已有享元
Flyweight GetFlyweight(const SharedState &shared_state)
{
std::string key = this->GetKey(shared_state);
if (this->flyweights_.find(key) == this->flyweights_.end())
{
std::cout << "FlyweightFactory: Can't find a flyweight, creating new one.\n";
this->flyweights_.insert(std::make_pair(key, Flyweight(&shared_state)));
}
else
{
std::cout << "FlyweightFactory: Reusing existing flyweight.\n";
}
return this->flyweights_.at(key);
}
// 打印享元缓存
void ListFlyweights() const
{
size_t count = this->flyweights_.size();
std::cout << "\nFlyweightFactory: I have " << count << " flyweights:\n";
for (std::pair<std::string, Flyweight> pair : this->flyweights_)
{
std::cout << pair.first << "\n";
}
}
};
// 客户端,通过转递key从享元工厂中获取享元。
// 将汽车信息记录至公安车辆管理数据库
void AddCarToPoliceDatabase(
FlyweightFactory &ff, const std::string &plates, const std::string &owner,
const std::string &brand, const std::string &model, const std::string &color)
{
std::cout << "\nClient: Adding a car to database.\n";
const Flyweight &flyweight = ff.GetFlyweight({brand, model, color});
flyweight.Operation({owner, plates});
}
int main()
{
// 客户端代码通常在应用程序的初始化阶段创建一堆预先填充的flyweights。
FlyweightFactory *factory = new FlyweightFactory({
{"Chevrolet", "Camaro2018", "pink"}, {"Mercedes Benz", "C300", "black"}, {"Mercedes Benz", "C500", "red"}, {"BMW", "M5", "red"}, {"BMW", "X6", "white"}});
factory->ListFlyweights();
AddCarToPoliceDatabase(*factory,
"CL234IR",
"James Doe",
"BMW",
"M5",
"red");
AddCarToPoliceDatabase(*factory,
"CL234IR",
"James Doe",
"BMW",
"X1",
"red");
factory->ListFlyweights();
delete factory;
return 0;
}
三、优缺点,适用场景
优点
- 如果程序中有很多相似对象,那么你将可以节省大量内存。
缺点
- 你可能需要牺牲执行速度来换取内存,因为他人每次调用享元方法时都需要重新计算部分情景数据。
- 为了使对象可以共享,需要将一些不能共享的状态外部化,这将增加程序的复杂性。
边栏推荐
- 机器学习笔记 - 时间序列的季节性
- Analysis and protection of heart blood dripping vulnerability (cve-2014-0160)
- [esp32-c3][rt-thread] run RT-Thread BSP minimum system based on esp32c3
- First knowledge - Software Testing
- Goto statement to realize shutdown applet
- 倍福CX5130换卡对已有的授权文件转移操作
- 倍福PLC通过程序获取系统时间、本地时间、当前时区以及系统时间时区转换
- G - Cow Bowling
- openlayers 绘制动态迁徙线、曲线
- 倍福通过CTU和TON实现时间片大小和数量的控制
猜你喜欢

Photoshop 2022 23.4.1增加了哪些功能?有知道的吗

Stream learning record

C# const详解:C#常量的定义和使用

自动化测试的局限性你知道吗?

Chapter 01_ Installation and use of MySQL under Linux

解中小企业之困,百度智能云打个样

记一次phpcms9.6.3漏洞利用getshell到内网域控

goto语句实现关机小程序

P2393 yyy loves Maths II

Beifu PLC passes MC_ Readparameter read configuration parameters of NC axis
随机推荐
软件测试测试常见分类有哪些?
Power Designer - Custom Comment button
[BSidesCF 2019]Kookie 1
Solution of Splunk iowait alarm
Detailed explanation of C const: definition and use of C constant
倍福Ethercat模块网络诊断和硬件排查的基本方法
深度解析当贝盒子B3、腾讯极光5S、小米盒子4S之间的区别
Deeply analyze the differences between dangbei box B3, Tencent Aurora 5S and Xiaomi box 4S
ES6模块
C语言:练习题二
HDU 5860
计组实践实验9——使用CMStudio设计基于分段模型机微程序指令(2)
别乱用 FULL_CASE 和 PARALLEL_CASE
详细讲解C语言11(C语言系列)
Electron official docs series: Contributing
Unit practice experiment 8 - using cmstudio to design microprogram instructions based on basic model machine (1)
使用SSH密钥对登陆服务器
Electron official docs series: References
[极客大挑战 2019]RCE ME 1
UVA5009 Error Curves三分