单件模式之土著人的可乐瓶

 

单件模式之土著人的可乐瓶


作者:
ABao.oO

下载源代码



  话说一群土著人生活地球的某个不为人知的地方,他们过着和谐、快乐的日子。但是好景不长,一只从天上掉下来的玻璃瓶打破了这美好的时光。这只玻璃瓶用处非常广泛,有的土著人用它来砸地瓜,有的用它来吹口哨,有的用它来擀蛇皮……,渐渐地大家干活、娱乐都离不开它了,于是产生了争抢使用可乐瓶的情况,为了获得原有的和谐气氛,一个土著人决定扔掉这个瓶子……
  剧情讲完了,我们先为这个瓶子定义一个类:

class CGlassBottle  
{
private:
	CGlassBottle();
public:
	virtual ~CGlassBottle();
public:
	static BOOL OnKnock();//砸
	static BOOL OnBlow();//吹
	static BOOL OnRoll();//擀
protected:
	static BOOL s_bUsed;//是否正在被使用
};
  我们定义一个土著人A类,假设他只用玻璃瓶砸地瓜:
class A//土著人A
{
public:
	void UseBottle()
	{
		CGlassBottle::OnKnock();
	};
};
  我们再定义一个土著人B类,假设他只用玻璃瓶吹口哨:
class B//土著人B
{
public:
	void UseBottle()
	{
		CGlassBottle::OnBlow();
	};
};
  现在我们定义土著人A、B类的对象,让他们执行UseBottle:
int main(int argc, char* argv[])
{
	A a;
	B b;
	a.UseBottle();//执行Knock
	b.UseBottle();//执行blow
	return 0;
}
我们来执行一下,看看结果:


图一 执行结果

  执行结果跟我们预期的一样,这就是传说中的类单件,土著人A用它来砸地瓜,土著人B用它来吹口哨。我个人对类单件的理解是这样的,类单件是对相似的函数块、功能块或其他模块进行封装,尽量不涉及类的属性。像二进制,十进制,十六进制字符串进行相互转换的函数,如:
class CNumFormat
{
private:
	CNumFormat();
public:
	static CString From2TO10(LPCTSTR lpszTxt2);
	static CString From2TO16(LPCTSTR lpszTxt2);
	static CString From10TO2(LPCTSTR lpszTxt2);
	static CString From10TO16(LPCTSTR lpszTxt2);
	static CString From16TO2(LPCTSTR lpszTxt2);
	static CString From16TO10(LPCTSTR lpszTxt2);
};
  在本例子中的CGlassBottle类,这样用也是可以的,但我们还可以把它设计得更好。在《深入浅出设计模式》中是这样定义单件模式的:确保一个类只有一个实例,并提供全局访问点。下面我们根据该定义对CGlassBottle类进行改进:
class CGlassBottle  
{
private:
	CGlassBottle();
public:
	virtual ~CGlassBottle();
public:
	bool OnKnock();//砸
	bool OnBlow();//吹
	bool OnRoll();//擀
public:
	static CGlassBottle s_GlassBottle;//定义
protected:
	bool m_bUsed;//是否正在被使用
};
  对土著人A、B类进行相应的修改:
class A//土著人A
{
public:
	void UseBottle()
	{
		CGlassBottle::s_GlassBottle.OnKnock();
	};
};
class B//土著人B
{
public:
	void UseBottle()
	{
		CGlassBottle::s_GlassBottle.OnBlow();
	};
};
  很多时候我们不希望s_GlassBottle暴露出来,而更希望通过函数调用来获取,于是增加一个获取s_GlassBottle的函数,同时把GlassBottle搞成私有静态成员,具体如下:
class CGlassBottle  
{
private:
	CGlassBottle();
public:
	virtual ~CGlassBottle();
public:
	bool OnKnock();//砸
	bool OnBlow();//吹
	bool OnRoll();//擀
public:
	static CGlassBottle* GetInstance()
	{
		return &s_GlassBottle;
	}
private:
	static CGlassBottle s_GlassBottle;//定义
protected:
	bool m_bUsed;//是否正在被使用
};
  土著人 A、B类在UseBottle()时进行如下修改:
class A//土著人A
{
public:
	void UseBottle()
	{
		CGlassBottle::GetInstance()->OnKnock();
	};
};
class B//土著人B
{
public:
	void UseBottle()
	{
		CGlassBottle::GetInstance()->OnBlow();
	};
};
  可能许多朋友都听说过延迟实例化这个概念,那我们这里也玩玩这个概念:
	class CGlassBottle  
	{
	private:
		CGlassBottle();
	public:
		virtual ~CGlassBottle();
	public:
		bool OnKnock();//砸
		bool OnBlow();//吹
		bool OnRoll();//擀
	public:
		static CGlassBottle* GetInstance()
		{
			static CGlassBottle s_GlassBottle;//定义
			return &s_GlassBottle;
		}	
	protected:
		bool m_bUsed;//是否正在被使用
};
  其实我也偏好这种用法,不知道在多线程下面会不会有问题(我只在单线程下玩,所以还没有发现过问题)。但是你会发现在调用GetInstance()的时候必须要在前面加上CGlassBottle::,在调用时像下面这样:
CGlassBottle::GetInstance()->OnKnock();
  这是不是会让人觉得啰嗦呢,至少对我来说很啰嗦,但我们还可以像下面这么处理:
#define GetGlassBottle() CGlassBottle::GetInstance()
用的时候就这么用“GetGlassBottle()->Knock();”,当然还可以对CGlassBottle进行改进,不知道这叫不叫改进:
class CGlassBottle  
{
private:
	CGlassBottle();
public:
	virtual ~CGlassBottle();
public:
	bool OnKnock();//砸
	bool OnBlow();//吹
	bool OnRoll();//擀
private:
	friend CGlassBottle* GetGlassBottle();

	static CGlassBottle* GetInstance()
	{
		static CGlassBottle s_GlassBottle;//定义
		return &s_GlassBottle;
	}	
protected:
	bool m_bUsed;//是否正在被使用
};
inline CGlassBottle* GetGlassBottle()
{
	return CGlassBottle::GetInstance();
}
  现在可以这样用了:
GetGlassBottle()->OnKnock();
  这样看起来是不是舒服多了。
  我这个人比较懒,一直喜欢像下面这样用,因为一直没有出现过问题,所以用得挺爽:
class CGlassBottle  
{
private:
	CGlassBottle();
public:
	virtual ~CGlassBottle();
public:
	bool OnKnock();//砸
	bool OnBlow();//吹
	bool OnRoll();//擀
private:
	friend CGlassBottle* GetGlassBottle();	
protected:
	bool m_bUsed;//是否正在被使用
};
inline CGlassBottle* GetGlassBottle()
{
	static CGlassBottle s_GlassBottle;//定义
	return &s_GlassBottle;
}
  文章到此结束,如有不妥之处,请来信告知。

参考文献:
  1.《设计模式-可复用面向对象软件的基础》-- 李英军等译
  2.《深入浅出设计模式》-- Eric Freeman,Elisabeth Freeman,^Kathy Sierra & Bert Bates著


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值