C#设计模式—— 单例模式(简单的说)

单例模式:确保一个类只有一个实例,并提供一个全局访问点。(定义)
概念拆解:
(1)确保一个类只有一个实例
(2)提供一个访问它的全局访问点
个人理解:
  一个类不被new,在类里的方法不被重复的new,在多线程调用实例时,确保只有一个实例在运行。
生活中的例子:
  一个国家只有一个总统。
简单的单例模式代码:
/// <summary>
/// 单例模式的实现
/// </summary>
public class Singleton
{
// 定义一个静态变量来保存类的实例
private static Singleton uniqueInstance;

// 定义私有构造函数,使外界不能创建该类实例
private Singleton()
{
}

/// <summary>
/// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
/// </summary>
/// <returns></returns>
public static Singleton GetInstance()
{
// 如果类的实例不存在则创建,否则直接返回
if (uniqueInstance == null)
{
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
》》在多线程中,需要确保一个实例。(我们可以使用线程锁lock来控制 )
 
   /// <summary>
    /// 单例模式的实现
    /// </summary>
    public class Singleton
    {
        // 定义一个静态变量来保存类的实例
        private static Singleton uniqueInstance;

        // 定义一个标识确保线程同步
        private static readonly object locker = new object();

        // 定义私有构造函数,使外界不能创建该类实例
        private Singleton()
        {
        }

        /// <summary>
        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance()
        {
            // 当第一个线程运行到这里时,此时会对locker对象 "加锁",
            // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
            // lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
            lock (locker)
            {
                // 如果类的实例不存在则创建,否则直接返回
                if (uniqueInstance == null)
                {
                    uniqueInstance = new Singleton();
                }
            }

            return uniqueInstance;
        }
    }
 
》》多线程的“双重锁定”(目的:为了减少不必要的开销)
   /// <summary>
    /// 单例模式的实现
    /// </summary>
    public class Singleton
    {
        // 定义一个静态变量来保存类的实例
        private static Singleton uniqueInstance;

        // 定义一个标识确保线程同步
        private static readonly object locker = new object();

        // 定义私有构造函数,使外界不能创建该类实例
        private Singleton()
        {
        }

        /// <summary>
        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance()
        {
            // 当第一个线程运行到这里时,此时会对locker对象 "加锁",
            // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
            // lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
            // 双重锁定只需要一句判断就可以了
            if (uniqueInstance == null)
            {
                lock (locker)
                {
                    // 如果类的实例不存在则创建,否则直接返回
                    if (uniqueInstance == null)
                    {
                        uniqueInstance = new Singleton();
                    }
                }
            }
            return uniqueInstance;
        }
    }

简单模拟网站计数功能

     public class Singleton
    {
         private static Singleton instance;//静态实例
         private static readonly object locker = new object();//静态锁
         public int count = 1;
         private Singleton() {//构造函数
             while (true)
             {
                 Console.ReadKey();
                 count += 1;
                 Console.WriteLine(count.ToString());
             }
         }

         public static Singleton GetInstance()//方法,方法中去实例化类.
         {
             if (instance == null)
             {
                 lock(locker)
                 {
                     if (instance == null)
                     {
                         instance = new Singleton();
                     }
                 }
             }
             return instance;
         }
    }

 在某个时候我只需要一个线程去处理事务,不想有多个实例时。例如我们建立一个数据库存取的管理类。类中有许多的方法。

    public class DBManager
    {
        private static DBManager uniqueInstance;//定义一个静态变量来保存类的实例
        private static readonly object locker = new object();//定义一个线程锁
        private static SQLiteHelp sqliteHelper;//实例化一个数据库连接

        #region 全局访问点
        private DBManager()
        {
            string dbPath = Application.StartupPath + "\Data.thl";
            sqliteHelper = new SQLiteHelp("data source=" + dbPath + ";Pooling=true;FailIfMissing=false");
        }
        /// <summary>
        /// 全局访问点
        /// </summary>
        /// <returns></returns>
        public static DBManager GetInstance()
        {
            if (uniqueInstance == null)
            {
                lock (locker)
                {
                    if (uniqueInstance == null)
                    {
                        uniqueInstance = new DBManager();
                    }
                }
            }
            return uniqueInstance;
        }
        #endregion

        #region 文件列表操作
        /// <summary>
        /// 插入路径
        /// </summary>
        /// <param name="path">路径</param>
        /// <returns></returns>
        public bool InsertFilePath(string path)
        {
            string sql = "insert into RunInfoList (FilePath,Status) values ('" + path + "','停止')";
            var affectedCount = sqliteHelper.ExecuteNonQuery(sql);
            if (affectedCount == 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 插入路径
        /// </summary>
        /// <param name="serverId">游服ID</param>
        /// <param name="path">路径</param>
        /// <returns></returns>
        public bool InsertFilePath(int serverId,string path)
        {
            string sql = "insert into RunInfoList (ServerId,FilePath,Status) values ('"+serverId+"','" + path + "','停止')";
            var affectedCount = sqliteHelper.ExecuteNonQuery(sql);
            if (affectedCount == 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="path">路径</param>
        /// <returns></returns>
        public bool DeleteFilePath(string path)
        {
            string sql = "delete from RunInfoList where FilePath = '" + path + "'";
            var affectedCount = sqliteHelper.ExecuteNonQuery(sql);
            if (affectedCount == 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 更新最后的备份时间
        /// </summary>
        /// <param name="path">路径</param>
        /// <returns></returns>
        public bool UpdateTime(string path)
        {
            string sql = "update RunInfoList set LastBackupTime=datetime('now') where FilePath = '" + path + "'";
            var affectedCount = sqliteHelper.ExecuteNonQuery(sql);
            if (affectedCount == 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 获取文件列表
        /// </summary>
        /// <returns></returns>
        public List<FileListInfo> GetFileList()
        {
            string sql = "select * from RunInfoList";
            var reader = sqliteHelper.ReturnDataReader(sql);
            List<FileListInfo> fileList = new List<FileListInfo>();
            while (reader.Read())
            {
                FileListInfo data = new FileListInfo();
                if (!Convert.IsDBNull(reader["ServerId"]))
                {
                    data.ServerId = Convert.ToInt32(reader["ServerId"]);
                }
                if (!Convert.IsDBNull(reader["FilePath"]))
                {
                    data.FilePath = reader["FilePath"].ToString();
                }
                if (!Convert.IsDBNull(reader["Status"]))
                {
                    data.Status = reader["Status"].ToString();
                }
                if (!Convert.IsDBNull(reader["LastBackupTime"]))
                {
                    data.LastBackTime = reader["LastBackupTime"].ToString();
                }
                fileList.Add(data);
            }
            return fileList;
        }

        /// <summary>
        /// 更新ServerId
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public bool UpdateServerId(string path,string serverid)
        {
            string sql = "update RunInfoList set ServerId='"+serverid+"' where FilePath = '" + path + "'";
            var affectedCount = sqliteHelper.ExecuteNonQuery(sql);
            if (affectedCount == 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        #endregion
}

说了单例模式的一些概念和代码,重要的是我们要怎么应用在实际的开发中?以下是我在博客园找到的关于单例的运用场景。

1. Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~ 
2. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
3. 网站的计数器,一般也是采用单例模式实现,否则难以同步。
4. 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
5. Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。
6. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。
7. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
8. 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
9. HttpApplication 也是单位例的典型应用。熟悉ASP.NET(IIS)的整个请求生命周期的人应该知道HttpApplication也是单例模式,所有的HttpModule都共享一个HttpApplication实例.
 
总结以上,不难看出:
  单例模式应用的场景一般发现在以下条件下:
  (1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
  (2)控制资源的情况下,方便资源之间的互相通信。如线程池等。
 
参考资料:http://terrylee.cnblogs.com/archive/2005/12/09/293509.html