八.创建型设计模式——Singleton Pattern(单例模式)
单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类,它提供全局访问的方法。单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行想整个系统提供这个实例。
UML类图如下:
类和对象之间的关系为:
1.Singleton(单例):提供了一个instance的方法,让客户可以使用它的唯一实例。内部实现只生成一个实例。
典型应用的顺序图如下:
-
实例1——负载均衡控制器
负载均衡器的实现就是单一的实例,对服务器的所以请求都通过一个了解服务器的状态对象来控制,因为个别的服务器可能会动态地开关。这个单例的类图如下:
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()
{
//通过“双检锁”模式支持多线程的应用
if (balancer == null)
{
//只有一个县城可以取得mutex
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();
}
}
}
//客户应用测试
class Client
{
[STAThread]
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.Read();
}
}
也可以在第一次调用getinstance方法就生成实例,直接了当。
public class Singleton
{
private static readonly Singleton instance = new Singleton();
//注意默认的构造函数为私有,所以不能直接创建它
private Singleton() { }
//公共属性返回唯一实例
public static Singleton Instance
{
get { return instance; }
}
}
-
优势和缺陷
Singleton单例模式为一个面向对象的应用程序提供了对象唯一的访问点,不管它实现何种功能,此种模式都为设计及开发团队提供了共享的概念。然而,Singleton对象类派生子类就有很大的困难,只有在父类没有被实例化时才可以实现。值得注意的是,有些对象不可以做成Singleton,比如.net的数据库链接对象(Connection),整个应用程序同享一个Connection对象会出现连接池溢出错误。另外,.net提供了自动废物回收的技术,因此,如果实例化的对象长时间不被利用,系统会认为它是废物,自动消灭它并回收它的资源,下次利用时又会重新实例化,这种情况下应注意其状态的丢失。
-
应用情景
下面的情景很适合应用单例模式:
1. 系统只需要一个实例的对象。
2. 客户调用类的单个实例只允许使用一个公共访问点。