本篇来看一下创建型模式中最常用的第三种模式:单例模式。仍然是先看两张图,复习模式类型,加深记忆。
定义:
单例模式:确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。
Singleton Pattern: Ensure a class has only one instance, and provide a global point of access to it.
要点:
某个类只能有一个实例
必须自行创建这个实例
必须自行向整个系统提供这个实例
最简单的实用案例就是windows操作系统中的任务管理器,还有负载均衡的唯一性等。
结构:
分类:
饿汉式单例类:无须考虑多个线程同时访问的问题;调用速度和反应时间优于懒汉式单例;资源利用效率不及懒汉式单例;系统加载时间可能会比较长
class EagerSingleton
{
private static EagerSingleton instance = new EagerSingleton();
private EagerSingleton() { }
public static EagerSingleton GetInstance()
{
return instance;
}
}
懒汉式单例类:实现了延迟加载;必须处理好多个线程同时访问的问题;需通过双重检查锁定等机制进行控制,将导致系统性能受到一定影响
class Singleton
{
private static Singleton instance=null;
private Singleton()
{
}
public static Singleton GetInstance()
{
if(instance==null)
instance=new Singleton();
return instance;
}
}
懒汉式防止不同进程重复调用,可以双重检查锁定:
class LazySingleton
{
private static LazySingleton instance = null;
//程序运行时创建一个静态只读的辅助对象
private static readonly object syncRoot = new object();
private LazySingleton() { }
public static LazySingleton GetInstance()
{
//第一重判断,先判断实例是否存在,不存在再加锁处理
if (instance == null)
{
//加锁的程序在某一时刻只允许一个线程访问
lock(syncRoot)
{
//第二重判断
if(instance==null)
{
instance = new LazySingleton(); //创建单例实例
}
}
}
return instance;
}
}
类图:
适用性:
系统
只需要一个实例对象
,或者因为资源消耗太大而
只允许创建一个对象
客户调用类的单个实例
只允许使用一个公共访问点
,除了该公共访问点,不能通过其他途径访问该实例
优点:
提供了
对唯一实例的受控访问
可以
节约系统资源
,
提高系统的性能
允许可变数目的实例(
多例类
)
缺点:
扩展困难
(缺少抽象层)
单例类的
职责过重
由于自动垃圾回收机制,可能会导致共享的单例对象的
状态丢失
案例1:(.NET代码)
using System;
namespace SingletonSample
{
class Program
{
static void Main(string[] args)
{
//创建四个LoadBalancer对象
LoadBalancer balancer1,balancer2,balancer3,balancer4;
balancer1 = LoadBalancer.GetLoadBalancer();
balancer2 = LoadBalancer.GetLoadBalancer();
balancer3 = LoadBalancer.GetLoadBalancer();
balancer4 = LoadBalancer.GetLoadBalancer();
//判断服务器负载均衡器是否相同
if (balancer1 == balancer2 && balancer2 == balancer3 && balancer3 == balancer4)
{
Console.WriteLine("服务器负载均衡器具有唯一性!");
}
//增加服务器
balancer1.AddServer("Server 1");
balancer1.AddServer("Server 2");
balancer1.AddServer("Server 3");
balancer1.AddServer("Server 4");
//模拟客户端请求的分发,如果输出结果全为同一个server,可以将i适当放大,例如改为"i < 100"
for (int i = 0; i < 10; i++)
{
string server = balancer1.GetServer();
Console.WriteLine("分发请求至服务器: " + server);
}
Console.Read();
}
}
}
using System;
using System.Collections;
namespace SingletonSample
{
class LoadBalancer
{
//私有静态成员变量,存储唯一实例
private static LoadBalancer instance = null;
//服务器集合
private ArrayList serverList = null;
//私有构造函数
private LoadBalancer()
{
serverList = new ArrayList();
}
//公有静态成员方法,返回唯一实例
public static LoadBalancer GetLoadBalancer()
{
if (instance == null)
{
instance = new LoadBalancer();
}
return instance;
}
//增加服务器
public void AddServer(string server)
{
serverList.Add(server);
}
//删除服务器
public void RemoveServer(string server)
{
serverList.Remove(server);
}
//使用Random类随机获取服务器
public string GetServer()
{
Random random = new Random();
int i = random.Next(serverList.Count);
return serverList[i].ToString();
}
}
}
案例2:(JAVA代码)
public class Singleton {
private static Singleton sing;
private Singleton() {
}
public static Singleton getInstance() {
if (sing == null) {
sing = new Singleton();
}
return sing;
}
}
public class Test {
public static void main(string[] args) {
Singleton sing = Singleton.getInstance();
Singleton sing2 = Singleton.getInstance();
System.out.println(sing);
System.out.println(sing2);
}
}