英文原文: https://sourcemaking.com/design_patterns/singleton

意图

  • 确保一个类只有一个实例,并提供一个访问其实例的全局点;
  • 封装 “即时初始化” (just-in-time initialization)或 “首次使用时初始化” (initialization on first use)。

问题

应用需要一个且唯一一个对象的实例。而且,延迟初始化(lazy initialization)和全局访问是必须的。

讨论

使得具有单一实例对象的类负责创建、初始化、访问和执行。声明这个实例作为一个私有静态数据成员。提供一个公共静态成员函数封装所有的初始化代码,同时提供对这个实例的访问。

任何时候,需要引用单一实例时,客户端(使用类名和范围精度操作符1)调用 accessor 函数。

只有满足所有下面三个标准时,才应该考虑单例模式:

  • 单个实例的所有权不能合理分配;
  • 延迟初始化是可取的;
  • 全局访问未另行规定;

如果单个成员实例的所有权,何时以及如何初始化,全局访问都不是问题,那么单例模式将不足以令人感兴趣。

单例模式可以扩展到支持访问包含大量实例的具体应用。

“静态成员函数访问器”(static member function accessor)方法将不会支持 Singleton类的子类。如果需要子类,参考本书中的讨论。

删除一个Singleton类/实例是一个有意义的设计问题。可查看John Vlissides在讨论中所说 "To Kill A Singleton" 。

结构

使得包含单一实例的类负责访问和在第一次使用时初始化。这个单一实例是一个私有静态属性。而 accessor 函数是一个公共静态方法。

示例

Singleton 模式确保这种类只有一个实例,并提供此实例的全局访问点。它根据 singleton set 命名,singleton set 定义了一个只包含一个元素的集合。美国总统办公室就是一个单例。美国宪法指定总统的选举方式,限制了其任期,并定义了继任的顺序。所以,在任何给定时间,最多只有一个有效的总统。不管这个有效的总统的个人身份,这个标题 “美国总统” 是一个全局访问点,识别在办公室的那个人。

清单

  1. 在 “单一实例” 类中,定义一个私有静态属性。
  2. 在这个类中,定义一个公有静态 accessor 函数。
  3. 在访问器(accessor)函数中,进行 “延迟初始化”(在首次使用时创建)。
  4. 定义所有构造体为 protected 或 private 。
  5. 客户端可能只能使用 accessor 函数来操控 Singleton 。

经验法则

  • Abstract Factory,Builder 和  Prototype  可以在它们实现中使用 Singleton 。
  • Facade 对象常常是 Singletons,因为其只需要唯一一个 Facade 对象。
  • 状态对象常常是 Singletons 。
  • Singleton 对于全局变量的优势是当你使用 Singleton 时,你绝对确信实例的数目,而且你可以改变你的思维和管理任何数量的实例。
  • Singleton 设计模式是最多被不恰当使用的模式之一。Singletons 只有在一个类必须只有一个实例,不能多,也不能少时,才能确定使用。设计者经常错误地使用 Singletons 替代全局变量。Singleton 出于意图和目的是一个全局变量。Singleton 并没有消除全局变量,它只是对其重命名。
  • 什么时候 Singleton 是不必要的?简短的答案:大多数时候。长答案:当以引用的方式传递一个对象资源给需要它的对象更容易的时候,而不是让对象全局访问资源。对于 Singletons,真正的问题是它们给你一个好借口,不要仔细考虑一个对象的合适的可见性。发现在公开和保护对象之间合适的平衡,对于维护灵活性是非常重要的。

因为我们组有使用全局变量的坏习惯,所以我组织了关于 Singleton 的学习小组。接下来,我发现 Singletons 到处出现,而与全局变量相关的问题一个都没有消失。对全局数据的问题的答案并不是把它变成 Singleton 。其答案是 “到底你们为什么使用全局变量?” 改变名字不能改变问题。实际上,这样,可能会使情况变坏,因为你有机会说,“哦,我没有那样做,我是这样做的” —— 即使这样和那样是同一个事情。

代码示例

Java Singleton in Java Singleton in Java
C++ Singleton in C++: Before and after Singleton in C++
PHP Singleton in PHP
Delphi Singleton in Delphi
Python Singleton in Python

译者注:

1、范围精度操作符 - scope resolution operator,即 "::"

[翻译] 单例(Singleton)的更多相关文章

  1. 跨应用程序域(AppDomain)的单例(Singleton)实现

    转载自: 跨应用程序域(AppDomain)的单例(Singleton)实现 - CorePlex代码库 - CorePlex官方网站,Visual Studio插件,代码大全,代码仓库,代码整理,分 ...

  2. OpenJDK源码研究笔记(十三):Javac编译过程中的上下文容器(Context)、单例(Singleton)和延迟创建(LazyCreation)3种模式

    在阅读Javac源码的过程中,发现一个上下文对象Context. 这个对象用来确保一次编译过程中的用到的类都只有一个实例,即实现我们经常提到的"单例模式". 今天,特意对这个上下文 ...

  3. spring mvc 的Controller类默认Scope是单例(singleton)的

    使用Spring MVC有一段时间了,之前一直使用Struts2,在struts2中action都是原型(prototype)的, 说是因为线程安全问题,对于Spring MVC中bean默认都是(s ...

  4. 【Java学习笔记之三十】详解Java单例(Singleton)模式

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

  5. 瞎扯设计模式1:单例模式 饿汉模式 懒汉模式 线程安全的单例 singleton 设计模式 java

    [原创声明]此文为本人原创,欢迎转载,转载请注明出处,作者链接~ http://www.cnblogs.com/m-yb/p/8833085.html 单例很常用,面试也经常被问,如:不用自定义锁怎么 ...

  6. JAVA中实现单例(Singleton)模式的八种方式

    单例模式 单例模式,是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例.即一个类只有一个对象实例. 基本的实现思路 单 ...

  7. Lumen开发:lumen源码解读之初始化(3)——单例(singleton)与中间件(Middleware)

    版权声明:本文为博主原创文章,未经博主允许不得转载. 今天来讲讲Lumen的singleton和Middleware,先来看看起始文件bootstrap/app.php / * | --------- ...

  8. 单例Singleton

    先提供一个完整版: // .h文件 @interface SingleTon : NSObject /** 获取单例对象 */ + (instancetype)sharedInstance; + (i ...

  9. 设计一个线程安全的单例(Singleton)模式

    在设计单例模式的时候.尽管非常easy设计出符合单例模式原则的类类型,可是考虑到垃圾回收机制以及线程安全性.须要我们思考的很多其它.有些设计尽管能够勉强满足项目要求,可是在进行多线程设计的时候.不考虑 ...

随机推荐

  1. python2.x提示这个错误:UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position

    查了好久下面这个方法可用: 发现应该是因为python2.x的默认编码是ascii,而代码中可能由utf-8的字符导致,解决方法是设置utf-8. 找到出错的文件,在import后增加下面几行: #! ...

  2. GIF图制作

    一.安装image 首先在cmd中敲入代码pip install imageio,以便制作动图 二.安装完之后便可读取gif了 在idle中输入代码 import imageio savename = ...

  3. 03-oracle数值函数

    --round(数值,想要保留的位数如1.2.3),作用:保留小数取值时四舍五入select round(678.656) 不保留小数,round(678.456,1) 保留一位小数,round(67 ...

  4. gps数据上传防止android系统休眠

    最近在做关于android手机端gps定时定位的功能,需要每隔几秒钟将gps定位获取的经纬度上传至后台,但是发现某些手机在屏幕黑屏,进入休眠状态后,后台就没有收到定位信息了,后来通过网上查找资料,发现 ...

  5. JS框架设计之模块加载系统

    任何语言一到大规模应用阶段,必然要拆封模块,有利于维护和团队协作,与Java走得最近的dojo率先引进了加载器,使用document.write与同步Ajax请求实现,后台dojo以JSONP的方法来 ...

  6. CentOS7 wget 安装Redis,开机启动配置

      安装 GCC yum install gcc yum install tcl 安装wget yum install wget 1. 下载Redis wget http://download.red ...

  7. CoreJava基础之构造器

    类的基本语法: 修饰词 class 类名{ 修饰词 类型 属性名: } 实例:public class Book{ int id; String name; String[] authors ={&q ...

  8. echart使用设置一个柱形的最小宽度

    因为echart的横坐标的个数不同会影响柱形图的宽度 如果只有三个月的就会是这样的 这样一来效果就不是很好,所以想做成如下效果 思路: 只是需要向xDate的值设置成想要的长度,如上图就是设置12,如 ...

  9. Helper Devise: could not find the `Warden::Proxy` instance on request environment

    在使用devise这个gem时,编写控制器层的单元测试,你需要在你的rspec帮助文件 rails_helper.rb里添加下面这一样 RSpec.configure do |config| conf ...

  10. Java反射获取当前项目下所有类,支持Servlet

    反射在很多时候要用,尤其自己编写框架时,那么如何获得当前项目下所有类呢!以下是本人封装的一个比较简洁的方法: [功能代码] //通过loader加载所有类 private List<Class& ...