您的位置:首页 > 其它

设计模式详细系列教程 (四) 无处不在的单例模式

2012-08-16 17:34 507 查看
谈到单例模式很多人应该知道它的作用,用单例时主要有三个要点需要注意:

一是某个类只能有一个实例;

二是它必须自行创建这个实例;

三是它必须自行向整个系统提供这个实例。

那么它如何实现这样的功能呢?让我们先看一下单例模式图:

【单例原理图】



【单例代码C#】

///////////////////////////////////////////////////////////
//  Singleton.cs
//  Implementation of the Class Singleton
//  Generated by Enterprise Architect
//  Created on:      16-八月-2012 15:43:21
//  Original author: 李龙生
///////////////////////////////////////////////////////////

namespace Singleton {
	public class Singleton {

		private static Singleton instance;

		~Singleton(){

		}

		public virtual void Dispose(){

		}

		/// <summary>
		/// 私有构造函数,防止外部类实例化它
		/// </summary>
		private Singleton(){

		}

		/// <summary>
		/// 全局访问点,返回本类实例
		/// </summary>
		public Instance GetInstance(){
			
			if (instance == null)
			{
				instance=new Singleton();
			}

			return null;
		}

	}//end Singleton

}//end namespace Singleton



【单例应用场景】

需要频繁实例化然后销毁的对象。
创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
有状态的工具类对象。
频繁访问数据库或文件的对象。
以及其他我没用过的所有要求只有一个对象的场景。
例如资源管理器、打印机、通信端口等,它们也符合开头介绍的三个要点。


【单例应用实例】

我们刚做完机房收费系统,那它来举例说明,这个系统中有一个功能是在线人数的显示,在线人数是在系统运行期间就一直存在的,属于全局对象,并且时时更新,访问数据库,可以用单例模式让这个对象实例化一次,提高执行效率。

同样,在我们看到的一些论坛、网站、CSDN、博客园等都有一种“在线用户人数”这一项功能,你是否知道这一功能是如何实现的,实现这个功能如果采用面向对象,每当有一个用户上线或者下线都会去实例化一个该对象,然后,像数据库或文件中插入删除数据,这就是单例模式场景的一种应用。

实现该功能的代码 C#

///////////////////////////////////////////////////////////
//  OnlineCounter.cs
//  Implementation of the Class OnlineCounter
//  Generated by Enterprise Architect
//  Created on:      16-八月-2012 15:43:21
//  Original author: 李龙生
///////////////////////////////////////////////////////////

namespace OnlineCounter {
	public class OnlineCounter {
        //私有属性,保存该类唯一实例
		private static OnlineCounter instance;
        //私有属性,保存在线人数
        private int onlineCount = 0;

		/// <summary>
		/// 私有构造函数,防止外部类实例化它,并初始化onlineCount值
		/// </summary>
		private OnlineCounter(){

            //从文件或者数据库表中读取数据,设置默认为10
            this.onlineCount = 10;
		}
        //用户登陆,在线人数加一
        public void IncreaseCount()
        {
            this.onlineCount++;
        }
        //用户下线,在线人数减一
        public void DecreaseCount()
        {
            this.onlineCount--;
        
        }
        //获取现在人数
        public int GetCount()
        {
            return onlineCount;
        }
		/// <summary>
		/// 全局访问点,返回本类实例
		/// </summary>
		public static OnlineCounter  GetInstance(){

            if ( instance == null )
            {
                instance = new OnlineCounter();
            }

			return instance;
		}

	}//end OnlineCounter

}//end namespace OnlineCounter



【进一步优化】

完美的人是不存在的,每个人对于完美的理解不同,当你觉的某某人好时,他可能是完美的。同样,完美的代码也不存在,上面代码解决了全局访问和实例化问题,却还有线程安全问题。

带来线程安全主要是因为实例化的对象时,恰巧两个对象同时访问该类全局函数,创建它的对象,个人感觉这种同年同月同日生同时同秒出生的概率是很小的,不过,还是存在需要进行安全处理。

给实例化对象部分的代码加锁:双重锁定







【C# 实现机制】

C#实现同上面类似这里不再累述,不同的是C#没有安全问题,安全由CLR解决,下面给出简单代码:

//阻止派生类发生,而派生类可能会增加实例
public sealed class Singleton
{
    //公共语言运行库负责初始化
    private static readonly Singleton instance = new Singleton();
    private Singleton()
    { 
    }
    public static Singleton GetInstance()
    {
        return instance;
    }

}



【懒汉与饿汉】

懒汉与饿汉从表面上看是非常简单,饿汉就想快点吃,快点把食物实例化出来,而懒汉呢不着急,什么时候实例化食物都无所谓。

用懒汉与饿汉比喻单例实例化时间的早晚,再恰当不过了。

C# 机制: 在第一次引用该类时实例化,第一种机制:在加载时实例化。

感觉这两种机制各有优缺点,但个人感觉对于很大的程序还是引用时实例化比较好,这样会占用少的系统资源,使空间合理利用。

希望大家可以学好单例,但想掌握好单例模式,需要更多的实践和应用,只有在实践中才能成长!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: