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;
        }
    }

簡單模擬網站計數功能html

     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;
         }
    }

 在某個時候我只須要一個線程去處理事務,不想有多個實例時。例如咱們創建一個數據庫存取的管理類。類中有許多的方法。sql

    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
相關文章
相關標籤/搜索