当前位置: 首页 > news >正文

Chapter9—享元模式

享元模式

1 概念

享元模式使用对象池来尽可能地减少对对象池中已经存在的对象的二次创建。对象池的实现和使用是享元模式的核心,享元模式是利用对象池减少内存的使用量,避免重复创建大量对象的设计模式。

2 意图(Intent)

运用共享技术有效地支持大量细颗粒度的对象。

3 动机(Motivate)

采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价(主要指内存需求方面的代价)。 如何在避免大量细粒度对象问题的同时,让外部客户程序仍然能够透明地使用面向对象的方式来进行操作?

4 类图结构

在这里插入图片描述

5 角色定义

  • Flyweight(享元接口):所有元件的高层规范,声明与外蕴状态互动的接口标准。
  • ConcreteFlyweight(享元实现):享元接口的元件实现类,自身维护着内蕴状态,且能接受并响应外蕴状态,可以有多个实现,一个享元对象可以被作为一个"元"。
  • FlyweightFactory(享元工厂):用来维护享元对象的工厂,负责对享元对象实例进行创建于管理,并对外提供获取享元对象的服务。

6 程序示例

共享网络设备

示例类图

在这里插入图片描述

抽象享元类INetworkDevice(网络设备类)

/*** @brief 抽象享元类INetworkDevice(网络设备类)*/
class INetworkDevice
{
public:INetworkDevice() = default;virtual ~INetworkDevice() = default;public:virtual string GetType() = 0;virtual void Use() = 0;
};

具体享元类Switch(交换机类)

/*** @brief 具体享元类Switch(交换机类)*/
class Switch: public INetworkDevice
{
public:Switch(const string& strType);~Switch() = default;public:string GetType() override;void Use() override;private:string m_strType;
};Switch::Switch(const string &strType): m_strType(strType)
{// ...
}string Switch::GetType()
{return m_strType;
}void Switch::Use()
{qDebug() << "Linked by switch, type is" << m_strType;
}

具体享元类Hub(集线器类)

/*** @brief 具体享元类Hub(集线器类)*/
class Hub: public INetworkDevice
{
public:Hub(const string& strType);~Hub() = default;public:string GetType() override;void Use() override;private:string m_strType;
};Hub::Hub(const string &strType): m_strType(strType)
{// ...
}string Hub::GetType()
{return m_strType;
}void Hub::Use()
{qDebug() << "Linked by Hub, type is" << m_strType;
}

享元工厂类DeviceFactory(网络设备工厂类)

/*** @brief 享元工厂类DeviceFactory(网络设备工厂类)*/
class DeviceFactory
{
public:DeviceFactory();~DeviceFactory();public:INetworkDevice* GetNetworkDevice(const string& strType);int GetTotalDevice();int GetTotalTerminal();private:vector<INetworkDevice*> m_vecDevice;int m_nTotalTerminal;
};DeviceFactory::DeviceFactory(): m_nTotalTerminal(0)
{INetworkDevice* pSwitch = new Switch("Cisco - WS - C2950 - 24");INetworkDevice* pHub = new Hub("TP - LINK - HF8M");m_vecDevice.push_back(pSwitch);m_vecDevice.push_back(pHub);
}DeviceFactory::~DeviceFactory()
{for (auto& pDevice:m_vecDevice){if (nullptr != pDevice){delete pDevice;pDevice = nullptr;}}
}INetworkDevice *DeviceFactory::GetNetworkDevice(const string &strType)
{if (string::npos != strType.find("Cisco")){++m_nTotalTerminal;return m_vecDevice[0];}else if (string::npos != strType.find("TP")){++m_nTotalTerminal;return m_vecDevice[1];}else{return nullptr;}
}int DeviceFactory::GetTotalDevice()
{return static_cast<int>(m_vecDevice.size());
}int DeviceFactory::GetTotalTerminal()
{return m_nTotalTerminal;
}

测试函数

/*** @brief 测试函数*/
void ClientTest()
{INetworkDevice* pSwitchA = nullptr;INetworkDevice* pSwitchB = nullptr;INetworkDevice* pSwitchC = nullptr;INetworkDevice* pHubA = nullptr;INetworkDevice* pHubB = nullptr;DeviceFactory* pDeviceFactory = new DeviceFactory();pSwitchA = pDeviceFactory->GetNetworkDevice("Cisco");pSwitchA->Use();pSwitchB = pDeviceFactory->GetNetworkDevice("Cisco");pSwitchB->Use();pSwitchC = pDeviceFactory->GetNetworkDevice("Cisco");pSwitchC->Use();pHubA = pDeviceFactory->GetNetworkDevice("TP");pHubA->Use();pHubB = pDeviceFactory->GetNetworkDevice("TP");pHubB->Use();qDebug() << "Total Device:" << pDeviceFactory->GetTotalDevice();qDebug() << "Total Terminal:" << pDeviceFactory->GetTotalTerminal();delete pDeviceFactory;
}

游戏背景图元

示例类图

在这里插入图片描述

绘图接口Drawable

/*** @brief 绘图接口Drawable*/
class Drawable
{
public:Drawable() = default;virtual ~Drawable() = default;public:virtual void Draw(int nX, int nY) = 0;
};

河流类 River

/*** @brief 河流类 River*/
class River: public Drawable
{
public:River();~River();public:void Draw(int nX, int nY) override;private:string m_strImage;
};River::River()
{m_strImage = "河流";
}River::~River()
{}void River::Draw(int nX, int nY)
{qDebug() << "在位置[ " << nX << ":" << nY << "]上绘制图片[" << m_strImage.c_str() << "]";
}

草地类 Grass

/*** @brief 草地类 Grass*/
class Grass: public Drawable
{
public:Grass();~Grass();public:void Draw(int nX, int nY) override;private:string m_strImage;
};Grass::Grass()
{m_strImage = "草地";
}Grass::~Grass()
{}void Grass::Draw(int nX, int nY)
{qDebug() << "在位置[ " << nX << ":" << nY << "]上绘制图片[" << m_strImage.c_str() << "]";
}

道路类 Road

/*** @brief 道路类 Road*/
class Road: public Drawable
{
public:Road();~Road();public:void Draw(int nX, int nY) override;private:string m_strImage;
};Road::Road()
{m_strImage = "道路";
}Road::~Road()
{}void Road::Draw(int nX, int nY)
{qDebug() << "在位置[ " << nX << ":" << nY << "]上绘制图片[" << m_strImage.c_str() << "]";
}

房屋类 House

/*** @brief 房屋类 House*/
class House: public Drawable
{
public:House();~House();public:void Draw(int nX, int nY) override;private:string m_strImage;
};House::House()
{m_strImage = "房屋";
}House::~House()
{}void House::Draw(int nX, int nY)
{qDebug() << "在位置[ " << nX << ":" << nY << "]上绘制图片[" << m_strImage.c_str() << "]";
}

图件工厂类 TileFactory

/*** @brief 图件工厂类 TileFactory*/
class TileFactory
{
public:TileFactory() = default;~TileFactory() = default;public:std::shared_ptr<Drawable> GetDrawable(const string& strImage);private:std::map<string, std::shared_ptr<Drawable>> m_mapImage;
};std::shared_ptr<Drawable> TileFactory::GetDrawable(const string &strImage)
{if (m_mapImage.end() != m_mapImage.find(strImage))return m_mapImage[strImage];if ("河流" == strImage){m_mapImage.insert({strImage, std::make_shared<River>()});}else if ("草地" == strImage){m_mapImage.insert({strImage, std::make_shared<Grass>()});}else if ("道路" == strImage){m_mapImage.insert({strImage, std::make_shared<Road>()});}else if ("房屋" == strImage){m_mapImage.insert({strImage, std::make_shared<House>()});}return m_mapImage[strImage];
}

测试函数

/*** @brief 测试函数*/
void ClientTest()
{TileFactory factory;factory.GetDrawable("河流")->Draw(10, 10);factory.GetDrawable("道路")->Draw(10, 10);factory.GetDrawable("草地")->Draw(10, 10);factory.GetDrawable("房屋")->Draw(10, 10);
}

7 思考小结

享元模式优点

  • 极大减少内存中对象数量,使得相同对象或相似对象在内存中只保存一份
  • 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享

享元模式缺点

  • 享元模式让系统更复杂,特别是需要分离内部状态和外部状态,这使得程序的逻辑复杂化
  • 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长

当一个系统有大量的对象,这些对象耗费大量的内存,对象的状态中的大部分都可以外部化,对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象代替,满足以上的这些条件的系统可以使用享元对象。最后,使用享元模式需要维护一个记录了系统已有的所有享元的表,而这需要耗费资源。因此,应当在有足够多的享元实例可供共享时才值得使用享元模式。

http://www.dtcms.com/a/422896.html

相关文章:

  • 常州网站建设公司案例怎样做企业学校网站
  • 建设网站对企业的重要性企业网站网页设计有哪些
  • SpringBoot结合Vue 播放 m3u8 格式视频
  • 网站推广目标关键词龙岩网站设计找哪家好
  • 【论文阅读】ASPS: Augmented Segment Anything Model for Polyp Segmentation
  • 精读C++20设计模式——结构型设计模式:享元模式
  • FT8430-LRT非隔离5V100MA电源芯片,满足小家电、智能照明、MCU供电需求,替代阻容降压(典型案例,电路图)
  • [论文阅读]Benchmarking Poisoning Attacks against Retrieval-Augmented Generation
  • 精读C++20设计模式:结构型设计模式:装饰器模式
  • (数据结构)链表OJ——刷题练习
  • 怎么做网站源码温州建网站
  • 云服务器做淘客网站苏州网站制作及推广
  • hive启动报错
  • (基于江协科技)51单片机入门:6.串口
  • UE5 小知识点 —— 09 - 旋转小问题
  • Git 暂存文件警告信息:warning: LF will be replaced by CRLF in XXX.java.
  • 石狮网站建设价格万网网站根目录
  • VBA ADO使用EXCEL 8.0驱动读取 .xlsx 格式表格数据-有限支持
  • freeswitch集成离线语音识别funasr
  • 建设网站管理规定源码做网站图文教程
  • Qt 入门:构建跨平台 GUI 应用的强大框架
  • Spring WebFlux调用生成式AI提供的stream流式接口,实现返回实时对话
  • 【学习笔记】高质量数据集
  • 微美全息科学院(WIMI.US):互信息赋能运动想象脑电分类,脑机接口精度迎来突破!
  • 协议 NTP UDP 获取实时网络时间
  • 公司网站可以分两个域名做吗残疾人网站服务平台
  • spark pipeline 转换n个字段,如何对某个字段反向转换
  • 学习React-18-useCallBack
  • 长沙制作网站的公司与传统市场营销的区别与联系有哪些
  • 从语言到向量:自然语言处理核心转换技术的深度拆解与工程实践导论(自然语言处理入门必读)