引言

  对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。单实例模式的UML图如下所示。

  

  一个类只能产生一个对象,该怎么实现呢?我们知道,可以通过类定义对象创建实例,或者通过new关键字产生对象;这个该怎么控制?

  创建对象时,都会根据输入的参数调用相应的构造函数,如果我们把构造函数设置为private私有访问权限不就不可以创建对象了吗?

  还有个问题:那我总要创建一个对象啊,单实例啊,不是无实例!咋办?有办法!可以定义一个公有的函数GetInstance()用于返回对象,这样就能创建辣!

  这又出现问题了,那这样做和将构造函数公有化有什么区别?你还是可以通过GetInstance()函数来创建多个对象...

  咋办?能不能只创建一次,设置个标志位?再次创建的时候判断一下?那得保证创建的这个变量的生存期不随对象的创建和销毁而变化,有了! 用static关键字声明吧。

  因为GetInstance()的返回类型为对应的类,所以需要定义一个含有该类的静态私有对象。

  举例说明一下

  皇帝一般来说,一个时期只存在一个,下面用大臣参拜皇帝的例子来说明单实例模式。CEmperor代表皇帝类,大臣在主函数中参拜皇帝。

 1 /*
 2 Time:2016-9-25 18:26:39
 3 Author:CodingMengmeng
 4 Description:Singleton.
 5 */
 6 #include <iostream>
 7 #include <tchar.h>
 8 using namespace std;
 9
10 class CEmperor{
11 private:
12     CEmperor();//注意:构造函数私有
13     virtual ~CEmperor();
14     static CEmperor* instance;//唯一实例
15
16 public:
17     static CEmperor* GetInstance();//工厂方法(用来获得实例)
18     static void emperorSay(void);//类中其它方法,尽量是static
19
20 };
21
22 CEmperor::CEmperor()
23 {
24     //世俗和道德约束你,目的就是不希望产生第二个皇帝
25     cout << "CEmperor Constructor" << endl;
26 }
27
28 CEmperor::~CEmperor()
29 {
30     if (instance != NULL)
31         delete instance;
32 }
33
34 //静态成员变量必须在类外初始化
35 CEmperor* CEmperor::instance = NULL;
36
37 CEmperor* CEmperor::GetInstance()
38 {
39     if (instance == NULL)    //如果未创建过,则new一个出来,如果new过了,则直接返回
40         instance = new CEmperor();
41     return instance;
42 }
43
44 void CEmperor::emperorSay()
45 {
46     cout << "我就是皇帝某某某...." << endl;
47 }
48
49 class CMinister{
50
51 };
52
53 int _tmain(int argc, _TCHAR* argv[])
54 {
55     for (int day = 0; day < 3; day++)
56     {
57         CEmperor* emperor = CEmperor::GetInstance();//当GetInstance()为static时,才能保证实例由类本身来创建,否则一个非static成员函数必须与特定对象搭配才能调用
58         emperor->emperorSay();
59     }
60
61     //三天见的皇帝都是同一个人。
62     return 0;
63 }

 

  运行结果:

  

  

  分析:

  当第一次调用GetInstance()时,instance为NULL,所以会执行instance=new Emperor();把这个新建的实例保存到静态成员instance,并返回这个指针。

  第二次到第N次调用GetInstance()时,由于instance不为空,所以会直接返回instance。也就是第一次调用GetInstance创建的那个实例,这样就实现了单实例。

要点

  显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例

  从具体实现角度来说,就是以下三点:一是单例模式的类只提供私有的构造函数二是类定义中含有一个该类的静态私有对象三是该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。上面的例子中,

static CEmperor* instance;

  即表示要点二:类定义中含有一个该类的静态私有对象;

static CEmperor* GetInstance();

  即表示要点三:该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。

单实例的应用

1、单实例模式的优点

  • 由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁的被创建、销毁,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显;
  • 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
  • 单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
  • 单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。

2、单实例模式的缺点

  • 单例模式没有接口,扩展很困难,若要扩展,除了修改代码没有第二种途径可以实现。单例模式为什么不能增加接口呢?因为接口对单例模式是没有任何的意义,它要求“自行实例化”,并且提供单一实例、接口或抽象类是不可能被实例化的。
  • 单例模式对测试是不利的。在并行开发环境中,如果单例模式没有完成,是不能进行测试的,没有接口也不能使用mock的方式虚拟一个对象。
  • 单例模式与单一职责原则有冲突。一个类应该只实现一个的逻辑,而不关心它是否是单例的,决定它是不是要单例是环境决定的,单例模式把“要单例”和业务逻辑融合也在一个类中。

3、单实例模式的使用场景

  在一个系统中,要求一个类有且仅有一个对象,如果出现多个对象就会出现“不良反应”时,则可以采用单例模式,具体的场景如下:

  • 要求生成唯一序列号的环境;
  • 在整个项目中需要有访问一个共享访问点或共享数据,例如一个Web页面上的计数器,可以不用每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
  • 创建一个对象需要消耗的资源过多,如要访问IO、访问数据库等资源;
  • 需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当然,也可以直接声明为static的方式);

4、单实例模式的注意事项

  在高并发情况下,请注意单例模式的线程同步问题。

转载于:https://www.cnblogs.com/codingmengmeng/p/5906583.html

设计模式(三)单实例模式相关推荐

  1. 设计模式三—抽象工厂模式

    设计模式三-抽象工厂模式 一.定义 抽象工厂模式是工厂方法模式的进一步抽象.如果产品簇中只有一种产品,则退化为工厂方法模式. 二.原理图 三.代码实例 * 苹果和土豆是园丁1的杰作 * 葡萄和西红柿是 ...

  2. 【Android 应用开发】Activity 返回堆栈管理 ( 栈内复用模式 singleTask | 单实例模式 singleInstance )

    文章目录 一. singleTask ( 栈内复用模式 ) Activity 实例在返回堆栈中的位置 二. singleTask ( 栈内复用模式 ) Activity 启动的五种情况 三. sing ...

  3. 设计模式_单实体模式

    Singleton 三要素:private 构造函数. public 静态方法. public 静态变量 单实例模式的三种线程安全实现方式(C++) 1 懒汉模式:即第一次调用该类实例的时候才产生一个 ...

  4. java设计模式---三种工厂模式

    工厂模式提供创建对象的接口. 工厂模式分为三类:简单工厂模式(Simple Factory), 工厂方法模式(Factory Method)和抽象工厂模式(Abstract Factory). GOF ...

  5. javascript设计模式-singleton(单例)模式

    singleton(单例)模式被熟知的原因是因为它限制了类的实例化次数只能一次,单例模式,在该实例不存在的勤快下,可以通过一个方法创建一个类来实现创建类的新实例:如果实例已经存在,则会简单返回该对象的 ...

  6. mysql工厂模式_设计模式-三种工厂模式实例

    1.简单工厂模式:代替new产生对象,产品的类型比较少时. 我们要获得三种不同的数据库对象,如Mysql,SQLserver,Oracle,它们拥有共同的特征,即可以进行抽象,简单工厂目的是将获得具体 ...

  7. java设计模式---三种工厂模式之间的区别

    简单工厂,工厂方法,抽象工厂都属于设计模式中的创建型模式.其主要功能都是帮助我们把对象的实例化部分抽取了出来,优化了系统的架构,并且增强了系统的扩展性. 本文是本人对这三种模式学习后的一个小结以及对他 ...

  8. 浅析设计模式(三)——抽象工厂模式

    抽象工厂模式(Abstract-Factory,创建型模式) 本文的结构: 一.抽象工厂模式的定义 二.抽象工厂模式的参与者及其角色 三.抽象工厂模式的类图 四.抽象工厂模式的示例 五.参考 一.抽象 ...

  9. Java经典23结构模型的设计模式(三)------附加代理模式、适配器型号、Facade模式的差异...

    本文介绍了7样的结构模型中的其余2种:轻量级.代理模式. 一.享元模式FlyWeight 享元模式比較简单且重要,在非常多场合都被用到.仅仅只是封装起来了用户看不到.其概念:运用共享内存技术最大限度的 ...

最新文章

  1. python怎么输出浮点数_python 零基础入门教程第 2 章:基本数据类型 (一)
  2. 创建销售订单BAPI一些心得
  3. Android之获取手机上的图片和视频缩略图thumbnails
  4. Java如何判断整数溢出,溢出后怎么得到提示?
  5. JavaWeb——springMVC、mybatis与spring的整合
  6. 23种设计模式(七)对象创建之工厂方法
  7. linux安装软件-rpm命令解析
  8. 刷题记录 CF每日一题打卡 2020.6月7-6月13
  9. 无人值守地磅电子汽车衡中称重系统传感器原理及应用
  10. 剪切音频matlab_怎样用matlab分割音频文件(wav)或其他
  11. tomcat修改端口号
  12. Linux之postfix邮件服务器搭建
  13. 平面几何----斜射影定理的应用
  14. iOS 组件化/模块化架构设计实践
  15. 七个好用且免费的在线代码编辑器,你喜欢哪个?
  16. Centos7 安装部署apache。简单易上手
  17. 起点小说免费看 Scrapy爬取起点小说网数据导入MongoDB数据
  18. yolov5_deepsort车流量跟踪计数
  19. 科大讯飞22周年发内部信:我们坚决反对内卷
  20. 【2022-05-26】小红书蒲公英x-s x-t

热门文章

  1. pytorch torch.narrow
  2. 1.8 其他正则化方法
  3. R语言聚类算法之系谱聚类(Hierarchical Method)
  4. 学计算机科学与技术会特效吗,女生学计算机科学与技术专业会不会很困难?看完你就明白了!...
  5. linux系统的文件系统tmpfs,linux里tmpfs文件系统
  6. 伦巴时间步的动作要领_拉丁舞教学视频,拉丁伦巴舞基本动作
  7. 神州数码携手IBM与红帽共商“新基建”机遇与挑战
  8. 红帽高级总监谈 OpenJDK 的未来:Java 的未来从未如此光明
  9. FastDFS学习总结(1)--FastDFS安装和部署
  10. c#位数不够0补充完_Java与C#比较,哪个语言更是适合你?