[Design Pattern]一种基于抽象类的Singleton模式的实现
namespace UtilityLibrary.PatternAndPractice
{
using System;
using System.Globalization;
using System.Reflection;
/// <summary>
/// The base class that implemented the singleton pattern
/// </summary>
/// <typeparam name="T">The target type needs the singleton feature. T must:
/// Have and only have a private default constructor</typeparam>
/// <exception cref="TypeInitializationException">
/// Throw a TypeInitializationException if the target type doesn't fullfile the condition:
/// Have and only have a private default constructor
/// </exception>
public abstract class SingletonBase<T>
where T : class
{
/// <summary>
/// A protected constructor which is accessible only to the sub classes.
/// </summary>
protected SingletonBase() { }
/// <summary>
/// Gets the singleton instance of this class.
/// </summary>
public static T Instance
{
get { return SingletonFactory.Instance; }
}
/// <summary>
/// The singleton class factory to create the singleton instance.
/// </summary>
class SingletonFactory
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static SingletonFactory()
{
}
/// <summary>
/// Prevents a default instance of the <see cref="SingletonBase<T>.SingletonFactory"/> class from being created.
/// </summary>
/// <remarks>Prevent the compiler from generating a default constructor.</remarks>
SingletonFactory()
{
}
internal static readonly T Instance = GetInstance();
/// <summary>
/// Gets the instance.
/// </summary>
/// <returns>The instance of type T</returns>
static T GetInstance()
{
var theType = typeof(T);
T instance;
try
{
instance = (T)theType.InvokeMember(
theType.Name,
BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic,
null,
null,
null,
CultureInfo.CurrentCulture);
}
catch (MissingMethodException ex)
{
string pattern =
"The type '{0}' must have a private constructor to be used in the Singleton pattern.";
string message = string.Format(CultureInfo.CurrentCulture, pattern, theType.FullName);
throw new TypeLoadException(message, ex);
}
return instance;
}
}
}
}
{
using System;
using System.Globalization;
using System.Reflection;
/// <summary>
/// The base class that implemented the singleton pattern
/// </summary>
/// <typeparam name="T">The target type needs the singleton feature. T must:
/// Have and only have a private default constructor</typeparam>
/// <exception cref="TypeInitializationException">
/// Throw a TypeInitializationException if the target type doesn't fullfile the condition:
/// Have and only have a private default constructor
/// </exception>
public abstract class SingletonBase<T>
where T : class
{
/// <summary>
/// A protected constructor which is accessible only to the sub classes.
/// </summary>
protected SingletonBase() { }
/// <summary>
/// Gets the singleton instance of this class.
/// </summary>
public static T Instance
{
get { return SingletonFactory.Instance; }
}
/// <summary>
/// The singleton class factory to create the singleton instance.
/// </summary>
class SingletonFactory
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static SingletonFactory()
{
}
/// <summary>
/// Prevents a default instance of the <see cref="SingletonBase<T>.SingletonFactory"/> class from being created.
/// </summary>
/// <remarks>Prevent the compiler from generating a default constructor.</remarks>
SingletonFactory()
{
}
internal static readonly T Instance = GetInstance();
/// <summary>
/// Gets the instance.
/// </summary>
/// <returns>The instance of type T</returns>
static T GetInstance()
{
var theType = typeof(T);
T instance;
try
{
instance = (T)theType.InvokeMember(
theType.Name,
BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic,
null,
null,
null,
CultureInfo.CurrentCulture);
}
catch (MissingMethodException ex)
{
string pattern =
"The type '{0}' must have a private constructor to be used in the Singleton pattern.";
string message = string.Format(CultureInfo.CurrentCulture, pattern, theType.FullName);
throw new TypeLoadException(message, ex);
}
return instance;
}
}
}
}
同时使用起来也是非常的简单直观:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using UtilityLibrary.PatternAndPractice;
namespace UtilityLibraryUnitTest.PatternAndPractice
{
[TestFixture]
class SingletonBaseTestSuite
{
class SingletonTest : SingletonBase<SingletonTest>
{
private SingletonTest()
{
}
public string Name { get { return "SingletonTest"; } }
}
class SingletonTestNegate : SingletonBase<SingletonTestNegate>
{
public SingletonTestNegate()
{
}
public string Name { get { return "SingletonTestNegate"; } }
}
class SingletonTestNegateToo : SingletonBase<SingletonTestNegate>
{
private int x;
private SingletonTestNegateToo(int x)
{
this.x = x;
}
public string Name { get { return "SingletonTestNegate"; } }
}
[Test]
public void SingletonBaseTest()
{
string s1 = SingletonTest.Instance.Name;
Assert.AreEqual(
"SingletonTest",
s1);
Assert.Catch<TypeInitializationException>(delegate{string s2 = SingletonTestNegate.Instance.Name;});
Assert.Catch<TypeInitializationException>(delegate { string s2 = SingletonTestNegateToo.Instance.Name; });
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using UtilityLibrary.PatternAndPractice;
namespace UtilityLibraryUnitTest.PatternAndPractice
{
[TestFixture]
class SingletonBaseTestSuite
{
class SingletonTest : SingletonBase<SingletonTest>
{
private SingletonTest()
{
}
public string Name { get { return "SingletonTest"; } }
}
class SingletonTestNegate : SingletonBase<SingletonTestNegate>
{
public SingletonTestNegate()
{
}
public string Name { get { return "SingletonTestNegate"; } }
}
class SingletonTestNegateToo : SingletonBase<SingletonTestNegate>
{
private int x;
private SingletonTestNegateToo(int x)
{
this.x = x;
}
public string Name { get { return "SingletonTestNegate"; } }
}
[Test]
public void SingletonBaseTest()
{
string s1 = SingletonTest.Instance.Name;
Assert.AreEqual(
"SingletonTest",
s1);
Assert.Catch<TypeInitializationException>(delegate{string s2 = SingletonTestNegate.Instance.Name;});
Assert.Catch<TypeInitializationException>(delegate { string s2 = SingletonTestNegateToo.Instance.Name; });
}
}
}