MyException - 我的异常网
当前位置:我的异常网» 设计模式 » 设计模式 一/23 单例模式

设计模式 一/23 单例模式

www.MyException.Cn  网友分享于:2013-09-19  浏览:0次
设计模式 1/23 单例模式

为什么将单例模式排名第一,很简单,面试的时候聊到设计模式,大概率就从单例模式开始入手,循循渐进。

当然,我们学习单例模式不是为了去应付面试,而是学好设计模式后,融汇贯通,应用于我们的设计,开发,项目中。

单例模式是最简单的设计模式之一

单例模式【Singleton Pattern】:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

两层含义:1,有且仅有一个实例

     2,有一个访问他的全局访问点

我们来想象一个场景,放眼全球,所有的党派,都只有一个主席(这应该没有例外吧)这个案例,如果要拜访他,是不是需要一个全局的访问点。

对于一个类来说,我们怎样保证他仅有一个实例,初步想到的是不准外部实例化,因为如果可以外部实例化,我就可以实例化无数个。那不准外部实例化,就只能内部了,那就动手修改内部的构造方法。

(敲黑板,划重点) 所有类都有构造方法,不编码则系统默认生成空的构造方法,若有显示定义的构造方法,默认的构造方法就会失效

如此,我们只需要显示的修改构造方法即可,既然不准外部调用,那我们用private修饰构造方法即可

第一步,控制外部实例化我们就做到了

    /// <summary>
    /// 党派
    /// </summary>
    public class Party
    {
        /// <summary>
        /// 私有化构造函数,不准外部实例化
        /// </summary>
        private Party()
        {
        }
    }
}
View Code

那我们需要一个主席,一个党派总不能群龙无首吧,于是我们定义一个主席,并且我们要提供一个访问的点吧,不然别人想和主席聊两句都找不到人

第二步,创建一个主席,并提供一个访问点

    /// <summary>
    /// 党派
    /// </summary>
    public class Party
    {
        /// <summary>
        /// 我是党派主席
        /// </summary>
        private static Party _chairman;

        /// <summary>
        /// 私有化构造函数,不准外部实例化
        /// </summary>
        private Party()
        {
        }

        /// <summary>
        /// 找主席
        /// </summary>
        /// <returns></returns>
        public static Party GetChairman()
        {
            if (_chairman == null)//主席不存在则创建一个主席
            {
                _chairman = new Party();
            }
            return _chairman;
        }
    }
}
View Code

哇哇哇~!!!私有构造函数,为什么这里可以调用啊,不是不让调用么!!!这是同一个类中,同一个类中,私有,公有,保护,都可以随意调用。

我们再让主席讲一句话

    /// <summary>
    /// 党派
    /// </summary>
    public class Party
    {
        /// <summary>
        /// 我是党派主席
        /// </summary>
        private static Party _chairman;

        /// <summary>
        /// 私有化构造函数,不准外部实例化
        /// </summary>
        private Party()
        {
        }

        /// <summary>
        /// 找主席
        /// </summary>
        /// <returns></returns>
        public static Party GetChairman()
        {
            if (_chairman == null)//主席不存在则创建一个主席
            {
                _chairman = new Party();
            }
            return _chairman;
        }

        public void Say()
        {
            Console.WriteLine("同志们好!");
        }
    }
View Code

这样我们的一个简单的单单例模式就算完成了,我们再看看如何调用

 class Program
    {
        static void Main(string[] args)
        {
            Party chairman = Party.GetChairman();
            chairman.Say();
        }
    }
View Code

那么问题来了,单线程操作的时候,以上没有问题,那多线程的时候呢,多个人同时访问主席,会不会可能产生多个主席呢,多个主席,是不是就违反了单例模式最基本的原则,仅有一个实例呢。多个主席,难道打一架,胜者为王么?

于是我们需要再次优化我们的代码

    /// <summary>
    /// 党派
    /// </summary>
    public class Party
    {
        /// <summary>
        /// 我是党派主席
        /// </summary>
        private static Party _chairman;

        /// <summary>
        /// 静态只读的进程辅助对象
        /// </summary>
        private static readonly object syncRoot = new object();

        /// <summary>
        /// 私有化构造函数,不准外部实例化
        /// </summary>
        private Party()
        {
        }

        /// <summary>
        /// 找主席
        /// </summary>
        /// <returns></returns>
        public static Party GetChairman()
        {
            lock (syncRoot)//锁你丫的
            {
                if (_chairman == null)//主席不存在则创建一个主席
                {
                    _chairman = new Party();
                }
            }
            return _chairman;
        }

        public void Say()
        {
            Console.WriteLine("同志们好!");
        }
    }
}
View Code

以上,再同一个时刻加了锁的那部分代码,只有一个线程可以进入。

如果lock不懂,我知道你们懒

lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放

 

那么问题又来了,为什么每一次都要锁,为什么,见一次主席那么那么难么?能不能没有创建的时候我才锁,有主席的时候我直接访问啊

当然可以,这就是双重锁定

    /// <summary>
    /// 党派
    /// </summary>
    public class Party
    {
        /// <summary>
        /// 我是党派主席
        /// </summary>
        private static Party _chairman;

        /// <summary>
        /// 静态只读的进程辅助对象
        /// </summary>
        private static readonly object syncRoot = new object();

        /// <summary>
        /// 私有化构造函数,不准外部实例化
        /// </summary>
        private Party()
        {
        }

        /// <summary>
        /// 找主席
        /// </summary>
        /// <returns></returns>
        public static Party GetChairman()
        {
            if (_chairman == null) //主席不存在,我再锁定,进行选举
            {
                lock (syncRoot) //锁你丫的
                {
                    if (_chairman == null) //主席不存在则创建一个主席
                    {
                        _chairman = new Party();
                    }
                }
            }
            return _chairman;
        }

        public void Say()
        {
            Console.WriteLine("同志们好!");
        }
    }
}
View Code

这里我们就先判断了主席是否存在,不存在,我们再闭门选举,等我们选举出来了,你再来访问。

我们既优化了执行,也保证了仅有一个主席,保证了多线程访问的安全性。

其实还有什么饿汉式,懒汉式的区别

从字面理解

饿汉,一开始我就实例化自己

        /// <summary>
        /// 我是党派主席
        /// </summary>
        private static Party _chairman = new Party();

懒汉,被引用时候,才实例化自己

        /// <summary>
        /// 我是党派主席
        /// </summary>
        private static Party _chairman ;
View Code

具体使用哪一种,应该根据实际情况来定,无优劣之分,值得注意的是线程安全


总结下

优点:

1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。

2、避免对资源的多重占用(比如写文件操作)。

缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

使用场景: 

1、要求生产唯一序列号。

2、计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。

3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。

以上就是关于单例模式的分享

一路前行,风雨无阻

 

1楼一抹微蓝
这么通俗易懂的文章竟然没人顶?

文章评论

2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
代码女神横空出世
代码女神横空出世
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
程序员应该关注的一些事儿
程序员应该关注的一些事儿
为什么程序员都是夜猫子
为什么程序员都是夜猫子
一个程序员的时间管理
一个程序员的时间管理
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
漫画:程序员的工作
漫画:程序员的工作
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
那些争议最大的编程观点
那些争议最大的编程观点
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
编程语言是女人
编程语言是女人
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
 程序员的样子
程序员的样子
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
Java程序员必看电影
Java程序员必看电影
程序员都该阅读的书
程序员都该阅读的书
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
旅行,写作,编程
旅行,写作,编程
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
我的丈夫是个程序员
我的丈夫是个程序员
中美印日四国程序员比较
中美印日四国程序员比较
总结2014中国互联网十大段子
总结2014中国互联网十大段子
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
老程序员的下场
老程序员的下场
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
程序员必看的十大电影
程序员必看的十大电影
如何成为一名黑客
如何成为一名黑客
10个调试和排错的小建议
10个调试和排错的小建议
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
鲜为人知的编程真相
鲜为人知的编程真相
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有