Singleton单例——对象创建型模式
意图
保证一个类在整个应用程序域中仅有一个实例,并提供一个访问它的全局访问点。
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
}
}