大话设计模式 —— 第二十六章《享元模式》C++ 代码实现

目录

定义

优点

缺点

应用场景


在面向对象程序设计过程中,有时会面临要创建大量相同或相似对象实例的问题。创建那么多的对象将会耗费很多的系统资源,它是系统性能提高的一个瓶颈。例如,围棋和五子棋中的黑白棋子,图像中的坐标点或颜色,局域网中的路由器、交换机和集线器,教室里的桌子和凳子等。这些对象有很多相似的地方,如果能把它们相同的部分提取出来共享,则能节省大量的系统资源。

也就是说在一个系统中如果有多个相同的对象,那么只共享一份就可以了,不必每个都去实例化一个对象。比如说一个文本系统,每个字母定一个对象,那么大小写字母一共就是52个,那么就要定义52个对象。如果有一个1M的文本,那么字母是何其的多,如果每个字母都定义一个对象那么内存早就爆了。那么如果要是每个字母都共享一个对象,那么就大大节约了资源。
  在Flyweight模式中,由于要产生各种各样的对象,所以在Flyweight(享元)模式中常出现Factory模式。Flyweight的内部状态是用来共享的,Flyweight factory负责维护一个对象存储池(Flyweight Pool)来存放内部状态的对象。Flyweight模式是一个提高程序效率和性能的模式,会大大加快程序的运行速度。


定义


享元模式是一种结构型设计模式。该模式主要是通过将对象的粒度细分,从而减少创建大量对象所占的内存。定义为:

  • 定义:使用共享对象有效的支持大量细粒度的对象

  • Flyweight(抽象享元角色)—— 定义对象的内部状态和外部状态及其对应的方法。
  • ConcreteFlyweight(具体享元角色)—— 实现抽象享元角色的方法,在具体的角色中,实现具体方法时需要注意将内部状态与外部状态区分开,不应出现二者同时被修改的方法。
  • unshareConcreteFlyweight(不可共享的享元角色)—— 该角色是不能使用共享技术的对象,一般在讨论线程安全时使用。
  • FlyweightFactory(享元工厂)—— 负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。

内部状态,就是各个对象不会随着环境的改变而改变的可共享部分;

外部状态,指对象随环境改变而改变的不可以共享的部分。内部状态和外部状态彼此互不影响,改变其中一个并不会改变另一个的行为。

下面用C++ 代码实现大话设计模式本章代码:

#include <iostream>
#include<string>
#include<map>
using namespace std;

//用户类
class User
{
private:
	string m_name;
public:
	User(string name)
	{
		m_name = name;
	}
	std::string GetName()
	{
		return m_name;
	}
};

//Flyweight类,此处为抽象网站类
class WebSite
{
public:
	virtual ~WebSite() = default;
	virtual void Use(User user) = 0;
};

//ConcreteFlyweight类,此处为具体网站类
class ConcreteWebSite :public WebSite
{
private:
	string m_name;
public:
	ConcreteWebSite(std::string name)
	{
		m_name = name;
	}
	void Use(User user)override
	{
		cout << "网站分类:" << m_name << "  用户:" + user.GetName() << endl;
	}
};

//FlyweightFactory类,此处为网站工程类
class WebSiteFactory
{
private:
	std::map<std::string, WebSite*> flyweights;
public:
	~WebSiteFactory()
	{	
		for (auto it = flyweights.begin(); it != flyweights.end(); ++it)
			delete it->second;
	}
	WebSite* GetWebSiteCategory(string key)
	{
		for (auto it = flyweights.begin(); it != flyweights.end(); ++it)
		{
			if (it->first == key)
				return it->second;
		}

		WebSite * website = new ConcreteWebSite(key);
		flyweights.insert(pair<std::string, WebSite*>(key, website));
		return website;
	}
	int GetWebSiteCount()
	{
		return flyweights.size();
	}
};

int main()
{
	WebSiteFactory f;

	WebSite* fx = f.GetWebSiteCategory("产品展示");
	fx->Use(User("小菜"));

	WebSite* fy = f.GetWebSiteCategory("产品展示");
	fy->Use(User("大鸟"));

	WebSite* fz = f.GetWebSiteCategory("产品展示");
	fz->Use(User("娇娇"));

	WebSite* fl = f.GetWebSiteCategory("博客");
	fl->Use(User("老顽童"));

	WebSite* fm = f.GetWebSiteCategory("博客");
	fm->Use(User("桃谷六仙"));

	WebSite* fn = f.GetWebSiteCategory("博客");
	fn->Use(User("南海鳄神"));

	cout << "得到网站分类总数:" << f.GetWebSiteCount() << endl;

	system("pause");
	return 0;
}


优点


  • 享元模式可以运用共享技术有效地支持大量细粒度的对象,大大减少对象的创建,降低系统的内存,使效率提高。

缺点


享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。
享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。


应用场景


  • 系统中存在大量相同或相似的对象,这些对象耗费大量的内存资源。
  • 大部分的对象可以按照内部状态进行分组,且可将不同部分外部化,这样每一个组只需保存一个内部状态。
  • 由于享元模式需要额外维护一个保存享元的数据结构,所以应当在有足够多的享元实例时才值得使用享元模式。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值