惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 司徒正美
Google Online Security Blog
Google Online Security Blog
博客园_首页
量子位
大猫的无限游戏
大猫的无限游戏
酷 壳 – CoolShell
酷 壳 – CoolShell
The Cloudflare Blog
Vercel News
Vercel News
GbyAI
GbyAI
Y
Y Combinator Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
C
Cisco Blogs
IT之家
IT之家
A
Arctic Wolf
P
Privacy International News Feed
G
GRAHAM CLULEY
腾讯CDC
Microsoft Security Blog
Microsoft Security Blog
Microsoft Azure Blog
Microsoft Azure Blog
美团技术团队
T
The Blog of Author Tim Ferriss
AWS News Blog
AWS News Blog
A
About on SuperTechFans
P
Proofpoint News Feed
I
Intezer
月光博客
月光博客
Cloudbric
Cloudbric
Google DeepMind News
Google DeepMind News
T
Tor Project blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
www.infosecurity-magazine.com
www.infosecurity-magazine.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
S
Securelist
Engineering at Meta
Engineering at Meta
爱范儿
爱范儿
F
Full Disclosure
V2EX - 技术
V2EX - 技术
Last Week in AI
Last Week in AI
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
人人都是产品经理
人人都是产品经理
C
Check Point Blog
I
InfoQ
S
Security Affairs
Simon Willison's Weblog
Simon Willison's Weblog
P
Palo Alto Networks Blog
F
Fortinet All Blogs
S
Security @ Cisco Blogs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
K
Kaspersky official blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security

博客园 - 周伟

域名解析文件hosts文件是什么?如何修改hosts文件? PowerDesigner 使用心得 实现TOMCAT服务下一个ip绑定多域名绑定的方法 CSV扩展类 C++导入导出CSV文件 struct+vector实现树结构 WebService 随写 mysql相关文章收集 Linux下两种自动启动Tomcat的方法 linux自动启动mysql LINUX下mysql的大小写区分设置 Jdom使用指南 vector+struct在数据接口中的应用 UML用例中使用和扩展意义 枚举和字符串互转 设计模式 Add Crash Reporting to Your Applications with the CrashRpt Library 设计模式——单键模式(singleton)C++实现 Singleton的C++实现 及相关问题
单件模式的C++标准实现
周伟 · 2009-05-13 · via 博客园 - 周伟

//****************************************************************
//3.5 SINGLETON(单件)—对象创建型模式
//1. 意图
//  保证一个类仅有一个实例,并提供一个访问它的全局访问点。
//2. 动机
//  对一些类来说,只有一个实例是很重要的。虽然系统中可以有许多打
//印机,但却只应该有一个打印假脱机( printer spooler),只应该有
//一个文件系统和一个窗口管理器。一个数字滤波器只能有一个A / D转换
//器。一个会计系统只能专用于一个公司。
//  我们怎么样才能保证一个类只有一个实例并且这个实例易于被访问呢?
//一个全局变量使得一个对象可以被访问,但它不能防止你实例化多个对象。
//  一个更好的办法是,让类自身负责保存它的唯一实例。这个类可以保
//证没有其他实例可以被创建(通过截取创建新对象的请求),并且它可
//以提供一个访问该实例的方法。这就是Singleton模式。
//3. 适用性
//  在下面的情况下可以使用Singleton模式
//.  当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
//.  当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改
//代码就能使用一个扩展的实例时。
//4. 结构
//5. 参与者
//.  Singleton
//— 定义一个GetInstance操作,允许客户访问它的唯一实例。GetInstance
//是一个类操作(即Smalltalk中的一个类方法和C++中的一个静态成员函数)。
//— 可能负责创建它自己的唯一实例。
//6. 协作
//.  客户只能通过Singleton的GetInstance操作访问一个Singleton的实例。
//7. 效果
//  Singleton模式有许多优点:
//1) 对唯一实例的受控访问因为Singleton类封装它的唯一实例,所以它可
//以严格的控制客户怎样以及何时访问它。
//2) 缩小名空间Singleton模式是对全局变量的一种改进。它避免了那些存
//储唯一实例的全局变量污染名空间。
//3) 允许对操作和表示的精化Singleton类可以有子类,而且用这个扩展类
//的实例来配置一个应用是很容易的。你可以用你所需要的类的实例在运行
//时刻配置应用。
//4) 允许可变数目的实例这个模式使得你易于改变你的想法,并允许
//Singleton类的多个实例。此外,你可以用相同的方法来控制应用所使用的
//实例的数目。只有允许访问Singleton实例的操作需要改变。
//5) 比类操作更灵活另一种封装单件功能的方式是使用类操作(即C++中的
//静态成员函数或者是Smalltalk中的类方法)。但这两种语言技术都难以改
//变设计以允许一个类有多个实例。
//  此外,C++中的静态成员函数不是虚函数,因此子类不能多态的重定义它们。
//8. 实现
 class Singleton{
  static std::auto_ptr<Singleton> m_pInstance;
 protected:
  //prevent user making our any instance by manually
  Singleton(){}
 public:
  ~Singleton(){}

  //Return this singleton class' instance pointer
  static Singleton* Instance(){
   if(!m_pInstance.get()){
    m_pInstance = std::auto_ptr<Singleton>(new Singleton());
   }
   return m_pInstance.get();
  }
 };

如上,实现一个单件本身是如此的简单,甚至无须废话。

怎样来使用它呢?
不要试图从这个类派生你的单件子类,那样的结果是不妥当的,如果你需要多个单件子类,还是使用下面的宏定义更为妥当:

#define DEFINE_SINGLETON(cls)\
 private:\
  static std::auto_ptr<cls> m_pInstance;\
 protected:\
  cls(){}\
 public:\
  ~cls(){}\
  static cls* Instance(){\
   if(!m_pInstance.get()){\
    m_pInstance = std::auto_ptr<cls>(new cls());\
   }\
   return m_pInstance.get();\
  }
#define IMPLEMENT_SINGLETON(cls) \
 std::auto_ptr<cls> cls::m_pInstance(NULL);

假定你需要实现一个单件类YY,这样书写:

class YY {
DEFINE_SINGLETON(YY);
public:
//your interfaces here...
};
在cpp文件中,书写:
IMPLEMENT_SINGLETON(YY);

需要引入这个类的实例的时候,使用这样的语句:

YY* pYY = YY::Instance();

这,就是全部。
如果需要定义其他的单件类,重复上面的定义,就可以了。

说了这么多,单件有什么用途?

请仔细阅读上面的动机部分。我再附加这些情况:

当想集中管理一个应用程序所需的所有配置时,可以声明一个CToolsOptions的类,其中包含配置属性集合。对于这个类的实例,显然是一个实例就够了;
当编写绘图程序时,考虑绘制矩形,圆形等分别使用CGraphTool派生的工具类,每个派生类负责处理具体的绘制动作和相关的UI相应逻辑。这些工具类典型的在被用户选择工具栏的图元按钮时被选中。依照这种模式,你应该对所有的图元工具从事注册工作,使得绘图程序了解运行时刻可以使用那些图元工具。同样的,负责管理注册信息的这个管理器也只需要一个实例就行了。

留心一下你的周围,单件实在是典型到不能再典型的例子,以至于随处可见。
各种设计模式在良好的设计代码中同样如此。
想要书写专家式的优雅代码,掌握模式是一种必须的手段。