文档章节

单例模式(Singleton Pattern)

自我修炼
 自我修炼
发布于 2017/02/09 20:56
字数 1614
阅读 4
收藏 0
点赞 0
评论 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
昆明
项目经理

暂无相关文章

CENTOS7防火墙命令记录

安装Firewall命令: yum install firewalld firewalld-config Firewall开启常见端口命令: firewall-cmd --zone=public --add-port=80/tcp --permanent firewall-cmd --zone=public --add-po......

cavion ⋅ 56分钟前 ⋅ 0

【C++】【STL】利用chromo来测量程序运行时间与日志时间打印精确到微秒

直接上代码吧,没啥好说的。头疼。 #include <iostream>#include <string>#include <ctime>#include <sstream>#include <iomanip>#include <thread>#include <chrono>using ......

muqiusangyang ⋅ 59分钟前 ⋅ 0

Mac环境下svn的使用

在Windows环境中,我们一般使用TortoiseSVN来搭建svn环境。在Mac环境下,由于Mac自带了svn的服务器端和客户端功能,所以我们可以在不装任何第三方软件的前提下使用svn功能,不过还需做一下简...

故久呵呵 ⋅ 今天 ⋅ 0

破解公司回应苹果“USB限制模式”:已攻破

本周四,苹果发表声明称 iOS 中加入了一项名为“USB 限制模式”的功能,可以防止 iPhone 在连接其他设备的时候被破解,并且强调这一功能并不是针对 FBI 等执法部门,为的是保护用户数据安全。...

六库科技 ⋅ 今天 ⋅ 0

MyBtais整合Spring Boot整合,TypeHandler对枚举类(enum)处理

概要 问题描述 我想用枚举类来表示用户当前状态,枚举类由 code 和 msg 组成,但我只想把 code 保存到数据库,查询处理,能知道用户当前状态,这应该怎么做呢?在 Spring 整合MyBatis 的时候...

Wenyi_Feng ⋅ 今天 ⋅ 0

synchronized与Lock的区别

# <center>王梦龙的读书笔记第一篇</center> ## <center>-synchronized与Lock的区别</centre> ###一、从使用场景来说 + synchronized 是能够注释代码块、类、方法但是它的加锁是和解锁使用一......

我不想加班 ⋅ 今天 ⋅ 0

VConsole的使用

手机端控制台打印输出,方便bug的排查。 首先需要引入vconsole.min.js 文件,然后在文件中创造实例。就能直接使用了。 var vConsole = new VConsole(); vConsole的文件地址...

大美琴 ⋅ 今天 ⋅ 0

Java NIO之字符集

1 字符集和编解码的概念 首先,解释一下什么是字符集。顾名思义,就是字符的集合。它的初衷是把现实世界的符号映射为计算机可以理解的字节。比如我创造一个字符集,叫做sex字符集,就包含两个...

士别三日 ⋅ 今天 ⋅ 0

Spring Bean基础

1、Bean之间引用 <!--如果Bean配置在同一个XML文件中,使用local引用--><ref bean="someBean"/><!--如果Bean配置在不同的XML文件中,使用ref引用--><ref local="someBean"/> 其实两种......

霍淇滨 ⋅ 今天 ⋅ 0

05、基于Consul+Upsync+Nginx实现动态负载均衡

1、Consul环境搭建 下载consul_0.7.5_linux_amd64.zip到/usr/local/src目录 cd /usr/local/srcwget https://releases.hashicorp.com/consul/0.7.5/consul_0.7.5_linux_amd64.zip 解压consu......

北岩 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部