文档章节

单例模式(Singleton Pattern)

自我修炼
 自我修炼
发布于 2017/02/09 20:56
字数 1614
阅读 4
收藏 0

单例模式

1. 啥时候使用单例模式
保证系统中某一服务有一个统一的入口,如:一个系统中可以存在多个打印服务,但只能有一个正在工作的任务;一个系统中只能有一个计时工具或序号生成器。

如何保证一个类只有一个实例并且这个实例易于被访问?定义一个全局变量可以保证对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没与其它实例被创建,并且它可以提供一个访问该实例的方法。

2. 单例模式的定义

单例模式(Singleton Pattern):确保某一个类有且仅有一个实例,并且自行实例化向整个系统提供这个实例。

分析:某个类仅有一个实例,并且必须是自身创建这个实例,还必须自身向整个系统提供这个实例。

3. 该模式中包含的角色及其职责

1)、Singleton:单实例
对整个系统提供有且仅有一个实例,并且是自身创建这个实例。

这里写图片描述

不废话了,看下面代码!

4. 撸代码

PHP的单例模式相对于其他语言是比较简单的,因为它不需要考虑多线程问题,下面我们给出两种代码实例(PHP和C#)。

先看下在PHP下的单例模式:


/** * 单实例角色:Singleton * 防止类被继承 */
final class Singleton
{
    /** * 定义一个私有的静态全局成员变量来保存该类的唯一实例 * @var Singleton */
    private static $instance;

    /** * 通过静态方法来构造对象实例 * */
    public static function getInstance()
    {
        //检查类是否已被实例化
        if (null === static::$instance) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    /** * 定义私有的构造函数 * 防止外部通过new关键字实例化对象 * 只允许自身实例化 */
    private function __construct()
    {
    }

    /** * 防止被复制或克隆 */
    private function __clone()
    {
    }

    /** * 防止反序列化创建该实例 */
    private function __wakeup()
    {
    }
}
/** * 测试单例模式 * */
class TestSingleton
{
    public function test(){
        //获取并创建单例对象
        $singleton = Singleton::getInstance();
    }
}

通过上例代码看出,在PHP中创建单例模式,必须遵循一下几点:
1)、有一个私有的类对象成员变量
2)、构造函数必须是私有的,防止通过new关键字被实例化
3)、__clone()和__wakeup()必须为私有的,防止复制、克隆和反序列化
4)、必须提供一个可供外界访问的静态方法,并通过此静态方法实现自身实例化对象。

在PHP中实现单例模式相对简单,因为它不需要考虑多线程问题,但C#中就必须要靠线程安全,如果C#在多线程中访问单例模式就有可能被创建多个对象,所以不得不考虑线程安全问题,要确保在多线程下访问单例模式依然是被创建一个实例对象。

C#代码如下:


    /// <summary>
    /// 单实例角色:Singleton
    /// </summary>
    public sealed class Singleton
    {
        /// <summary>
        /// 定义一个私有的静态全局成员变量来保存该类的唯一实例
        /// </summary>
        private static Singleton instance = null;
        /// <summary>
        /// 定义一个只读静态对象,且这个对象是在程序运行时创建
        /// 必须为引用类型,确保访问同一地址
        /// </summary>
        private static readonly object syncObject = new object();
        /// <summary>
        /// 定义私有的构造函数
        /// 防止外部通过new关键字实例化对象
        /// 只允许自身实例化
        /// </summary>
        private Singleton() { }
        /// <summary>
        /// 通过静态方法来构造对象实例
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance()
        {
            //第一次判断:主要判断单例对象是否已被实例化
            if (instance == null)
            {
                //锁住引用类型对象,进行同步操作
                //必须为引用类型,因为引用类型的变量地址是同一内存地址
                lock (syncObject)
                {
                    //第二次判断:主要是防止可能延迟加载或缓存,造成创建多个实例
                    if (instance == null)
                    {
                        instance = new Singleton();
                    }
                }
            }

            return instance;
        }
    }

通过上例代码看出,在C#或含有线程操作的面向对象语言中,必须遵循一下几点:
1)、有一个私有的类对象成员变量
2)、有一个私有的静态只读引用类型的对象变量,并且该对象在程序运行时被创建。
3)、构造函数必须是私有的,防止通过new关键字被实例化
4)、必须提供一个可供外界访问的静态方法,并通过此静态方法实现自身实例化对象。
并且在此方法内必须进行两次检查对象实例是否被创建,防止可能延迟加载或缓存,造成创建多个实例。

5. 单例模式的优点

实例控制

单例模式会防止其他对象实例化其自身的单例对象的副本,从而确保所有对象都访问唯一实例。

灵活性

因为类控制了实例化过程,所以类可以灵活更改实例化过程。

6. 单例模式的缺点

开销

虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。

对象生存期

不能解决删除单个对象的问题。在提供内存管理的语言中(c#),只有单例类能够导致实例被取消分配,因为它包含该实例的私有引用。

滥用单例带来的一些负面问题

如果为了节省资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;现在很多面向对象语言(java、C#)的运行环境都提供了自动垃圾回收的技术,因此,如果实例化的对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致对象状态的丢失。

7. 使用场景

系统只需要一个实例对象,如系统要求提供一个唯一的入口,或者考虑资源消耗太大而只允许创建一个实例。

© 著作权归作者所有

共有 人打赏支持
自我修炼
粉丝 0
博文 9
码字总数 11400
作品 0
昆明
项目经理

暂无文章

ppwjs之bootstrap文字排版:字体大小写设置

<!DOCTYPT html><html><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><title>ppwjs欢迎您</title><link rel="icon" href="/favicon.ico" ......

ppwjs
21分钟前
0
0
线性代数入门

线性代数的概念对于理解机器学习背后的原理非常重要,尤其是在深度学习领域中。它可以帮助我们更好地理解算法内部到底是怎么运行的,借此,我们就能够更好的做出决策。所以,如果你真的希望了...

牛奋Debug
35分钟前
0
0
开发5分钟,调试2小时 - 该如何debug?

几年来我在答疑群、论坛、公众号、知乎回答的各种问题,没有一万也有八千。其中有三分之二以上都是在帮人看报错,帮人 debug(调试代码)。 可以说,会不会 debug,有没有 debug 的意识,懂不...

crossin
36分钟前
0
1
SQL count(*) 和count(1)的区别

开发中经常会使用这两个聚合函数,作用都是用来统计记录行,今天查找资料发现,其实这两个函数并没有区别, 实践才是检验的标准,首先看执行计划(表是我自己建立的): 可以看到,两个执行计...

一曲图森破
40分钟前
1
0
区块链100讲:详解区块链之P2P网络

1 P2P网络 如果我们简单来看 P2P 技术,它的应用领域已经非常广泛了,从流媒体到点对点通讯、从文件共享到协同处理,多种领域都有它的身影出现。 同样的,P2P 的网络协议也有很多,比较常见的...

HiBlock
58分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部