设计模式之单例模式(创建型设计模式)
先说一段废话记录一下生活吧
又是一年毕业季,临近毕业,最近当然是在忙毕业设计了,今天查重报告下来了,查重率百分之二十八点多,要求百分之二十,真他妈shit了,加上天气炎热,最近很是烦躁,心情像一坨屎,每天上午死在宿舍,下午去篮球场,不过还有nba可以看,最近几场东西部决赛看的真是心脏不太好,昨天骑士和凯子抢七,老詹是真牛批,一个人扛着一个队硬是拿下了比赛,今天火箭和勇士抢七,本来想看我火在主场将西部决赛冠军收入囊中,但是没有保罗的火箭就是不太稳啊,喜欢登哥但是有时候总是掉链子,尤其今天的火箭27中0,我他么更是shit了.怎么说呢,明年接着来吧.
最近不知道看些什么,写些什么,还是写写设计模式吧,之前看过一些设计模式,没有记录下来,这次写一下整理整理吧.
========================================================================
单例模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
简单来说,我的对象由我自己来创建(单例当然只创建一个对象了),但是我可以给你们使用.
注意:
- 1、单例类只能有一个实例。
- 2、单例类必须自己创建自己的唯一实例。
- 3、单例类必须给所有其他对象提供这一实例。
主要解决:一个全局使用的类频繁地创建与销毁。
何时使用:当您想控制实例数目,节省系统资源的时候。
优点: 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
使用场景: 1、要求生产唯一序列号。
2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
然后我们来看一下单例模式的类图,如下图所示:
简单的说一下吧:
1.首先我们要有一个私有的构造方法,这样就能满足这个对象只能由我们自己创建的这个条件了
2.然后呢,我们提供一个私有的变量,用来存放这个唯一的实例
3.提供一个方法,返回这个唯一的实例(当然我们要进行一下判断了)
接下来我们可以简单的写一个单例类
namespace Singleton { /// <summary> /// 这是单例类 /// </summary> public class Unique { //提供一个变量来存储唯一的实例 private static Unique uniqueInstance; //提供一个私有的构造器 private Unique() { } //提供一个方法供其他类进行调用 public static Unique GetUniqueInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton.Unique(); } return uniqueInstance; } public void Show() { Console.WriteLine("单例中的方法"); } } }
namespace Singleton { class Program { static void Main(string[] args) { Unique unique = Unique.GetUniqueInstance(); unique.Show(); Console.ReadKey(); } } }
写到这,是不是觉得很简单呢,当然了,因为我们是单线程的程序,所以不会出现问题.
那我们考虑一下多线程的情况,假如现在有两个线程,其中一个线程执行到了GetUniqueInstance()方法,判断等于空,接着会去创建单例对象,这时第二个线程也来了,同样也执行到了GetUniqueInstance().但是呢,这时第一个线程还没有将对象创建出来(new一个对象哪有那么容易,当然是需要时间的了,就像你找女朋友一样),所以判断也为空,接着也去创建这个单例对象,这种情况是不是就创建了两个单例对象呢,这当然是错的,违背了我们只创建一个对象的初衷,所以我们要解决多线程的问题.
================================以下多线程=========================================
菜鸟教程上介绍了6种创建单例模式的方式,其中一种是不能保证线程安全的,也就是和我们上边写的类似,其余5种分别是:1 懒汉式线程安全,2 饿汉式,3 双检锁/双重校验锁,4 登记式/静态内部类,5 枚举
下面我先简单介绍一下饿汉式
饿汉式,就是一个饥饿的汉子(此处一个猥琐的表情),也就是在单例类内部的变量直接去把对象创建出来,而不是在GetUniqueInstance()中给这个变量赋值,(这个过程实在java类加载时初始化,对应的.net是哪个步骤我还不太清除,希望大神看到这能够指点迷津,给我留言哦)是CLR吗,底层我还没研究过...
下面我们来改造一下
public class Unique { //提供一个变量来存储唯一的实例 private static Unique uniqueInstance = new Unique (); //提供一个私有的构造器 private Unique() { } //提供一个方法供其他类进行调用 public static Unique GetUniqueInstance() { return uniqueInstance; } public void Show() { Console.WriteLine("单例中的方法"); } }
这就改造好了,很简单的,尝试一下
接着看一下双检锁/双重校验锁吧
//双层判断 中间加锁 public class Unique { //提供一个变量来存储唯一的实例 private static Unique uniqueInstance; //标识对象 可以锁这个对象 private static readonly object obj = new object(); //提供一个私有的构造器 private Unique() { } //提供一个方法供其他类进行调用 public static Unique GetUniqueInstance() { if (uniqueInstance == null) { //没有这层判断也可以,但是每次都是先锁对象,再去判断,加锁解锁耗时间,所以有这层判断更好 lock (obj) { if (uniqueInstance == null) { uniqueInstance = new Unique(); } } } return uniqueInstance; } public void Show() { Console.WriteLine("单例中的方法"); } }
之前一直认为这个双重锁就是懒汉模式,因为他比较懒,使用的时候才去创建,java中的懒汉模式使用到了synchronized关键字,也就是同步方法.C#中同步方法我还没想起来是哪个关键字,唉,才疏学浅,菜的一批,大家就自行百度吧
写到这也差不多了,剩下还有几种就不写了,有点饿,该去吃晚饭了
当然了,最后一句,欢迎指正,欢迎留言,欢迎转载(转载最好把我的博客地址贴上)