一、 单例(Singleton)模式
单例模式的特点:
-
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其它对象提供这一实例。
单例模式应用:
-
- 每台计算机可以有若干个打印机,但只能有一个Printer Spooler,避免两个打印作业同时输出到打印机。
- 一个具有自动编号主键的表可以有多个用户同时使用,但数据库中只能有一个地方分配下一个主键编号。否则会出现主键重复。
二、 Singleton模式的结构:
Singleton模式包含的角色只有一个,就是Singleton。Singleton拥有一个私有构造函数,确保用户无法通过new直接实例它。
除此之外,该模式中包含一个静态私有成员变量instance与静态公有方法Instance()。Instance方法负责检验并实例化自己,然后存储在静态成员变量中,
以确保只有一个实例被创建。(关于线程问题以及C#所特有的Singleton将在后面详细论述)。
三、 在什么情形下使用单例模式:
使用Singleton模式有一个必要条件:在一个系统要求一个类只有一个实例时才应当使用单例模式。
反过来,如果一个类可以有几个实例共存,就不要使用单例模式。
注意:
不要使用单例模式存取全局变量。这违背了单例模式的用意,最好放到对应类的静态成员中。
不要将数据库连接做成单例,因为一个系统可能会与数据库有多个连接,并且在有连接池的情况下,应当尽可能及时释放连接。
Singleton模式由于使用静态成员存储类实例,所以可能会造成资源无法及时释放,带来问题。
/// <summary> /// 单例(Singleton)模式 /// </summary> class Program { static void Main(string[] args) { LoadBalancer b1 = LoadBalancer.GetLoadBalancer(); LoadBalancer b2 = LoadBalancer.GetLoadBalancer(); LoadBalancer b3 = LoadBalancer.GetLoadBalancer(); LoadBalancer b4 = LoadBalancer.GetLoadBalancer(); // 同一个实例? if ((b1 == b2) && (b2 == b3) && (b3 == b4)) Console.WriteLine("Same instance"); //做负载均衡 Console.WriteLine(b1.Server); Console.WriteLine(b2.Server); Console.WriteLine(b3.Server); Console.WriteLine(b4.Server); Console.ReadLine(); } } /// <summary> /// 单例模式——现实世界的例子 /// Singleton 单例(LoadBalancer) /// </summary> public class LoadBalancer { private static LoadBalancer balancer; private ArrayList servers = new ArrayList(); private Random random = new Random(); //受保护的 构造函数 protected LoadBalancer() { // 可用的服务器列表 servers.Add("ServerI"); servers.Add("ServerII"); servers.Add("ServerIII"); servers.Add("ServerIV"); servers.Add("ServerV"); } //方法 定义静态方法确保同时只有一个实例在操作 public static LoadBalancer GetLoadBalancer() { //支持多线程应用程序通过 // “双重检查锁定”模式,避免了 // 锁定每次方法调用 //balancer = null; if (balancer == null) { // 只有一个线程可以获得互斥锁 Mutex mutex = new Mutex(); mutex.WaitOne(); if (balancer == null) balancer = new LoadBalancer(); mutex.Close(); } return balancer; } public string Server { get { // 简单,但有效的随机负载均衡器 int r = random.Next(servers.Count); return servers[r].ToString(); } } }