Singleton(單例)——物件建立型模式

CodingPioneer發表於2018-10-16

意圖

保證一個類在整個應用程式域中僅有一個例項,並提供一個訪問它的全域性訪問點。

Signleton模式的優點

1、對唯一例項的受控訪問。因為Singleton類封裝它的唯一例項,所以它可以嚴格的控制客戶怎樣以及何時訪問它。
2、縮小名空間。Singleton模式是對全域性變數的一種改進。它避免了那些儲存唯一例項的全域性變數汙染名空間。
3、允許對操作和表示的精化。Singleton類可以有子類,而且用這個擴充套件類的例項來配置一個應用是很容易的。
4、允許可變資料的例項。這個模式使得你易於改變你的想法,並允許Singleton類的多個例項。此外,你可以用相同的方法來控制應用所使用的例項的數目。只有允許訪問Singleton例項的操作需要改變。
5、比類操作更靈活。

典型應用場景

單例應用最多的地方就是讀取配置檔案,並在程式邏輯中通過Singleton類的例項訪問配置檔案的配置項。

實現要點

單例類設計的要點如下:

1、在類中定義私有(private)、靜態(static)的本類物件,用於儲存全域性唯一例項。
2、把(預設)構造方法定義為私有(private)。
3、定義獲取本類例項的靜態方法或靜態屬性。

案例程式碼

通過單例模式實現封裝對xml配置檔案的讀取操作。
xml配置檔案程式碼如下:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <!--工廠ID-->
  <add key="FactoryID" value="1" />
  <!--單機/網路:0為單機,1為網路-->
  <add key="NetType" value="1" />
  <!--網路伺服器連線檢測模式:0-網路庫檢測,1-Ping檢測-->
  <add key="CheckConnectMode" value="1" />
  <!--網路資料庫伺服器IP地址-->
  <add key="NetDbServerIP" value="127.0.0.1" />
  <!--本地資料庫-->
  <add key="DataSource.Local" value="DataSource1" />
  <!--本地曲線庫-->
  <add key="DataSource.Curve" value="DataSource2" />
  <!--工藝回溯資料庫-->
  <add key="DataSource.BackView" value="DataSource3" />
  <!--自定義裝置名稱,用於更新SysKeyValue表後進行介面資料更新-->
  <add key="Customer.EquipName" value="FeedingCustomer" />
  <!--機臺編碼-->
  <add key="EquipCode" value="01001" />
  <!--訊息視窗顯示模式,0-顯示3秒自動關閉,1-手動關閉-->
  <add key="MessageDialogMode" value="0" />
</configuration>

Singleton類程式碼如下:

using System;
using System.Collections.Generic;
using System.Xml;
using System.Text;
using System.IO;

namespace Mesnac.Basic
{
    /// <summary>
    /// 組態工程執行配置解析類
    /// </summary>
    public class RunSchema
    {
        #region 定義變數

        private string _projectPath = String.Empty;            //組態工程路徑
        private string _eventConfigPath = String.Empty;        //事件處理(Action)配置檔案路徑
        private string _runSchemaFilePath = "RunSchema.xml";   //執行結構配置檔案路徑

        private Dictionary<string, string> _runSchemaDic = new Dictionary<string, string>();

        #endregion

        #region 定義屬性

        public Dictionary<string, string> RunSchemaDic
        {
            get
            {
                if (_runSchemaDic.Count == 0)
                {
                    ParseFromRunSchema();
                }
                return _runSchemaDic;
            }
            private set
            {
                _runSchemaDic = value;
            }
        }
        /// <summary>
        /// 組態工程路徑
        /// </summary>
        public string ProjectPath
        {
            get { return this._projectPath; }
            set { this._projectPath = value; }
        }

        /// <summary>
        /// 事件處理(Action)配置檔案路徑
        /// </summary>
        public string EventConfigPath
        {
            get { return this._eventConfigPath; }
            set { this._eventConfigPath = value; }
        }

        #endregion

        #region 單例模式實現

        private static RunSchema _this;     //私有靜態例項,儲存全域性作用域中的唯一例項

        /// <summary>
        /// 靜態例項屬性
        /// </summary>
        public static RunSchema Instance
        {
            get
            {
                if (null == _this)
                    _this = new RunSchema();
                return _this;
            }
        }

        /// <summary>
        /// 私有構造方法
        /// </summary>
        private RunSchema()
        {
            this._runSchemaDic = new Dictionary<string, string>();
        }

        #endregion

        #region 基本資訊
        public string FilePath()
        {
            return Path.Combine(this._projectPath, this._runSchemaFilePath);
        }
        #endregion

        #region 檢測配置檔案是否存在
        /// <summary>
        /// 檢測配置檔案是否存在(先檢測組態工程目錄,在檢測事件處理(Action)配置檔案路徑)
        /// </summary>
        /// <returns>存在返回true,否則返回false</returns>
        public bool Exists()
        {
            string runSchemaFile = FilePath();
            string runSchemaFile2 = Path.Combine(this._eventConfigPath, this._runSchemaFilePath);
            if (File.Exists(runSchemaFile) || File.Exists(runSchemaFile2))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        #endregion

        #region 解析執行環境主配置檔案RunSchema.xml
        /// <summary>
        /// 解析執行環境主配置檔案RunSchema.xml
        /// </summary>
        public void ParseFromRunSchema()
        {
            try
            {
                //如果組態工程目錄(MCProject)下有RunSchema檔案,則首先以組態工程目錄下的檔案為配置檔案,
                //否則以事件處理(Action)配置檔案所在的目錄下的RunSchema檔案為準
                string runSchemaFile = FilePath();
                Dictionary<string, string> dic = new Dictionary<string, string>();
                if (!File.Exists(runSchemaFile))
                {
                    runSchemaFile = Path.Combine(this._eventConfigPath, this._runSchemaFilePath);
                }
                if (File.Exists(runSchemaFile))
                {
                    XmlDocument doc = new XmlDocument();
                    doc.Load(runSchemaFile);
                    XmlNodeList nodeList = doc.GetElementsByTagName("add");
                    foreach (XmlNode node in nodeList)
                    {
                        string key = node.Attributes["key"].Value;
                        if (!dic.ContainsKey(key))
                        {
                            string value = node.Attributes["value"].Value;
                            dic.Add(key, value);
                        }
                        else
                        {
                            //存在重複鍵
                            ICSharpCode.Core.LoggingService<RunSchema>.Error("配置檔案中存在重複鍵的配置項,key = " + key);
                        }
                    }
                }
                else
                {
                    //配置檔案不存在
                    ICSharpCode.Core.LoggingService<RunSchema>.Warn("應用程式配置檔案不存在!");
                }
                this._runSchemaDic = dic;
            }
            catch (Exception ex)
            {
                ICSharpCode.Core.LoggingService<RunSchema>.Error(ex.Message);
                throw ex;
            }
        }
        /// <summary>
        /// 儲存配置資訊
        /// </summary>
        /// <param name="dic"></param>
        /// <param name="runSchemaFile"></param>
        public void UpdateToRunSchema(Dictionary<string, string> dic)
        {
            string runSchemaFile = FilePath();
            if (dic != null && dic.Count > 0)
            {
                XmlDocument doc = new XmlDocument();
                XmlElement root = doc.CreateElement("configuration");
                foreach (string key in dic.Keys)
                {
                    XmlElement eAdd = doc.CreateElement("add");
                    XmlAttribute eAttKey = doc.CreateAttribute("key");
                    eAttKey.Value = key;
                    XmlAttribute eAttValue = doc.CreateAttribute("value");
                    eAttValue.Value = dic[key];
                    eAdd.Attributes.Append(eAttKey);
                    eAdd.Attributes.Append(eAttValue);
                    root.AppendChild(eAdd);
                }
                doc.AppendChild(root);
                doc.Save(runSchemaFile);
            }
            ParseFromRunSchema();
        }
        /// <summary>
        /// 更新配置節點至檔案
        /// </summary>
        /// <param name="key">要更新的配置項</param>
        /// <param name="newValue">要更新的配置項的值</param>
        public void UpdateNodeValueToRunSchema(string key, string newValue)
        {
            try
            {
                string runSchemaFile = FilePath();
                if (File.Exists(runSchemaFile))
                {
                    XmlDocument doc = new XmlDocument();
                    doc.Load(runSchemaFile);
                    XmlNodeList nodeList = doc.GetElementsByTagName("add");
                    bool flag = false;
                    foreach (XmlNode node in nodeList)
                    {
                        if (node.Attributes["key"].Value == key)
                        {
                            node.Attributes["value"].Value = newValue;
                            flag = true;
                            break;
                        }
                    }
                    if (!flag)
                    {
                        XmlElement eAdd = doc.CreateElement("add");
                        XmlAttribute eAttKey = doc.CreateAttribute("key");
                        eAttKey.Value = key;
                        XmlAttribute eAttValue = doc.CreateAttribute("value");
                        eAttValue.Value = newValue;
                        eAdd.Attributes.Append(eAttKey);
                        eAdd.Attributes.Append(eAttValue);
                        doc.DocumentElement.AppendChild(eAdd);
                    }
                    doc.Save(runSchemaFile);
                }
                else
                {
                    //配置檔案不存在
                    ICSharpCode.Core.LoggingService<RunSchema>.Warn("應用程式配置檔案不存在!");
                }
            }
            catch (Exception ex)
            {
                ICSharpCode.Core.LoggingService<RunSchema>.Error(ex.Message);
                throw ex;
            }
            ParseFromRunSchema();
        }

        #endregion

        #region 獲取RunSchema配置檔案中配置項的值
        /// <summary>
        /// 獲取RunSchema配置檔案中配置項的值
        /// </summary>
        /// <param name="key">配置型</param>
        /// <param name="defaultValue">獲取不到時的預設值</param>
        /// <returns>返回對應配置項的值</returns>
        public string GetConfigValue(string key, string defaultValue)
        {
            string value = string.Empty;
            if (this.RunSchemaDic.TryGetValue(key, out value))
            {
                return value;
            }
            return defaultValue;
        }

        public bool GetConfigValue(string key, bool defaultValue)
        {
            string value = GetConfigValue(key, String.Empty);
            bool result = defaultValue;
            if (bool.TryParse(value, out result))
            {
                return result;
            }
            else
            {
                return defaultValue;
            }
        }

        public int GetConfigValue(string key, int defaultValue)
        {
            string value = GetConfigValue(key, String.Empty);
            int result = defaultValue;
            if (int.TryParse(value, out result))
            {
                return result;
            }
            else
            {
                return defaultValue;
            }
        }

        #endregion

        #region 判斷Schema檔案是否存在

        /// <summary>
        /// 判斷Schema檔案是否存在
        /// </summary>
        /// <returns>存在返回true,失敗返回false</returns>
        public bool IsSchemaExists()
        {
            string runSchemaFile = FilePath();
            if (File.Exists(runSchemaFile))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        #endregion
    }
}

相關文章