/// <summary> /// 单例模式 Singleton Pattern /// geovindu,Geovin Du edit /// </summary> public class Database { /// <summary> /// /// </summary> private Database() { } /// <summary> /// /// </summary> public static Database Instance { get; } = new Database(); } /// <summary> /// /// </summary> public class MyDatabase { /// <summary> /// /// </summary> private MyDatabase() { Console.WriteLine("Initializing database"); } /// <summary> /// /// </summary> private static Lazy<MyDatabase> instance = new Lazy<MyDatabase>(() => new MyDatabase()); /// <summary> /// /// </summary> public static MyDatabase Instance => instance.Value; } /// <summary> /// /// </summary> public interface IDatabase { int GetPopulation(string name); } /// <summary> /// /// </summary> public class SingletonDatabase : IDatabase { /// <summary> /// /// </summary> private Dictionary<string, int> capitals; /// <summary> /// /// </summary> private static int instanceCount; /// <summary> /// /// </summary> public static int Count => instanceCount; /// <summary> /// /// </summary> private SingletonDatabase() { Console.WriteLine("Initializing database"); capitals = File.ReadAllLines( Path.Combine( new FileInfo(typeof(IDatabase).Assembly.Location) .DirectoryName, "capitals.txt") ) .Batch(2) .ToDictionary( list => list.ElementAt(0).Trim(), list => int.Parse(list.ElementAt(1))); } /// <summary> /// /// </summary> /// <param name="name"></param> /// <returns></returns> public int GetPopulation(string name) { return capitals[name]; } /// <summary> /// laziness + thread safety /// </summary> private static readonly Lazy<SingletonDatabase> instance = new Lazy<SingletonDatabase>(() => { instanceCount++; return new SingletonDatabase(); }); public static IDatabase Instance => instance.Value; } /// <summary> /// /// </summary> public class SingletonRecordFinder { /// <summary> /// /// </summary> /// <param name="names"></param> /// <returns></returns> public int TotalPopulation(IEnumerable<string> names) { return names.Sum(name => SingletonDatabase.Instance.GetPopulation(name)); } } /// <summary> /// /// </summary> public class ConfigurableRecordFinder { /// <summary> /// /// </summary> private IDatabase database; /// <summary> /// /// </summary> /// <param name="database"></param> public ConfigurableRecordFinder(IDatabase database) { this.database = database; } /// <summary> /// /// </summary> /// <param name="names"></param> /// <returns></returns> public int GetTotalPopulation(IEnumerable<string> names) { return names.Sum(name => database.GetPopulation(name)); } } /// <summary> /// /// </summary> public class DummyDatabase : IDatabase { /// <summary> /// /// </summary> /// <param name="name"></param> /// <returns></returns> public int GetPopulation(string name) { return new Dictionary<string, int> { ["alpha"] = 1, ["beta"] = 2, ["gamma"] = 3 }[name]; } } /// <summary> /// /// </summary> public class OrdinaryDatabase : IDatabase { /// <summary> /// /// </summary> private readonly Dictionary<string, int> cities; /// <summary> /// /// </summary> public OrdinaryDatabase() { Console.WriteLine("Initializing database"); cities = File.ReadAllLines( Path.Combine( new FileInfo(typeof(IDatabase).Assembly.Location) .DirectoryName, "capitals.txt") ) .Batch(2) .ToDictionary( list => list.ElementAt(0).Trim(), list => int.Parse(list.ElementAt(1))); } /// <summary> /// /// </summary> /// <param name="name"></param> /// <returns></returns> public int GetPopulation(string name) { return cities[name]; } }
/// <summary> /// 单例模式 Singleton Pattern /// geovindu,Geovin Du edit /// </summary> public sealed class Singleton { #region Singleton implementation using static constructor //The following line is discussed in analysis section. //private static readonly Singleton Instance = new Singleton(); private static readonly Singleton Instance; private static int TotalInstances; /* * Private constructor is used to prevent * creation of instances with 'new' keyword * outside this class. */ /// <summary> /// /// </summary> private Singleton() { Console.WriteLine("--Private constructor is called."); Console.WriteLine("--Exit now from private constructor."); } /* * A static constructor is used for the following purposes: * 1. To initialize any static data; * 2. To perform a specific action only once. * * The static constructor will be called automatically before * * i. You create the first instance; or * ii.You refer to any static members in your code. * */ /// <summary> /// Here is the static constructor /// </summary> static Singleton() { // Printing some messages before you create the instance Console.WriteLine("-Static constructor is called."); Instance = new Singleton(); TotalInstances++; Console.WriteLine($"-Singleton instance is created.Number of instances:{ TotalInstances}"); Console.WriteLine("-Exit from static constructor."); } /// <summary> /// /// </summary> public static Singleton GetInstance { get { return Instance; } } /* * If you like to use expression-bodied read-only * property, you can use the following line (C# v6.0 onwards). */ //public static Singleton GetInstance => Instance; #endregion /* The following line is used to discuss the drawback of the approach. */ /// <summary> /// /// </summary> public static int MyInt = 25; }
调用:
Console.WriteLine("***单例模式 Singleton Pattern Demonstration.***\n"); /*The following line is used to discuss the drawback of the approach.*/ //Console.WriteLine($"The value of MyInt is :{Singleton.MyInt}"); // Private Constructor.So,you cannot use the 'new' keyword. //Singleton s = new Singleton(); // error Console.WriteLine("Trying to get a Singleton instance, called firstInstance."); Singleton firstInstance = Singleton.GetInstance; Console.WriteLine("Trying to get another Singleton instance, called secondInstance."); Singleton secondInstance = Singleton.GetInstance; if (firstInstance.Equals(secondInstance)) { Console.WriteLine("The firstInstance and secondInstance are the same."); } else { Console.WriteLine("Different instances exist."); } // var rf = new SingletonRecordFinder(); var names = new[] { "Seoul", "Mexico City" }; var ci = names[0].ToString(); int tp = rf.TotalPopulation(names); Console.WriteLine(tp); var db = new DummyDatabase(); var rf2 = new ConfigurableRecordFinder(db); int t= rf2.GetTotalPopulation(new[] { "alpha", "gamma" }); ; Console.WriteLine(t); db.GetPopulation("gamma"); var db2 = SingletonDatabase.Instance; // works just fine while you're working with a real database. var city = "Tokyo"; Console.WriteLine($"{city} has population {db2.GetPopulation(city)}"); Console.WriteLine($"{names[0]} has population {db2.GetPopulation(names[0])}"); Console.Read();
输出:
***单例模式 Singleton Pattern Demonstration.*** Trying to get a Singleton instance, called firstInstance. -Static constructor is called. --Private constructor is called. --Exit now from private constructor. -Singleton instance is created.Number of instances:1 -Exit from static constructor. Trying to get another Singleton instance, called secondInstance. The firstInstance and secondInstance are the same. Initializing database 34900000 4 Tokyo has population 33200000 Seoul has population 17500000