概述:像Windows系统的任务管理器一样,你无论打开多少次,始终显示的一个窗口。如何保证一个类只有一个实例并且这个实例易于被访问呢,定义一个统一的全局变量可以确保对象随时可以被访问,但不能防止创建多个对象。一个最好的办法就是让类自身负责创建和保存它的唯一实例,并保证不创建其他实例,它还提供了一个访问该实例的方法,这就是单例模式的动机。。一点都不鸡冻-_-||。。
单例模式的定义:
单例模式:确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。
Singleton Pattern:Ensure a class has only one instance, and provide a global point of access to it.
单例模式是一种对象创建型模式。单例模式有三个要点:一是某个类只有一个实;二是它必须自行创建这个实例;三是它必须像整个系统提供这个实例。
单例模式的结构:
单例模式是结构最简单的设计模式,它只包含一个类,即单例类。
单例模式的实现:
public class SingletonPattern { //静态私有成员变量 private static SingletonPattern instance = null; //私有化构造函数 private SingletonPattern() { } //静态私有工厂方法返回唯一实例 public static SingletonPattern GetIstance() { if (instance == null) instance = new SingletonPattern(); return instance; } }
从代码可以看出在实现单例模式的时候,需要注意一下三点:
1:私有化构造函数private
2:提供一个自身静态私有成员变量
3:提供一个公有的静态工厂方法
饿汉式单例(Eager Singleton):
一:饿汉模式,代码如下图所以:
public class EagerSingleton { private static EagerSingleton instance = new EagerSingleton(); private EagerSingleton() { } public static EagerSingleton GetInstance() { return instance; } }
当类被加载的时候,静态变量instance会被初始化,此时类的私有构造函数会被调用,单例类唯一实例将被创建。
二:懒汉模式
与饿汉模式单例类相同的是,懒汉式单例类(Lazy Singleton)的构造函数也是私有的,与饿汉式单例类不同的是,懒汉式单例类第一次被引用时将自己实例化,在懒汉式单例类加载时不会将自己实例化。
从图中可以看出在懒汉单例类中,不是定义在静态变量时实例化单例类,而是在第一次调用静态工厂的时实例化单例类。
代码如下:
public 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; } }
从代码中可以看到加锁了,为什么加锁呢? 是因为懒汉式单例存在一个严重的问题:如果在高并发、多线程环境下实现懒汉式单例,在某一时刻可能会有多个线程需要使用单例对象,即会有多个线程同时调用GetInstance()方法,可能会造成多个实例对象,这将违背单例模式的设计意图。为了防止生成多个单例对象,需要使用lock关键字,lock关键字表示锁定的代码片段成为临界区,可以确保一个线程位于代码的临界区。另一个线程不能进入临界区。如果其他线程视图进入锁定的代码,则将一直等待,知道该对象被释放为止。
饿汉式单例与懒汉式单例进行比较:
饿汉式单例在类加载的时候就将自己实例化,它的优点在于无需考虑多个线程同时访问的问题,可以确保实例的唯一性。从调用速度来讲,由于单例对象一开始就得以创建,因此要优于懒汉式单例。但是无论系统在运行时是否需要使用该单例对象,由于在类加载时该对象就需要创建,因此从资源利用效率角度来京,饿汉式单例不急懒汉式单例,而且在系统加载时有序需要创建饿汉式单例对象,加载时间会比较长。
懒汉式单例在第一次使用时创建,无需一直占用系统资源,实现了延迟加载,但是必须处理好多个线程同时访问的问题,特别是当单例类作为资源控制器,在实例化时必然会涉及资源的初始化,而资源的初始化需要耗费大量的事件,这意味着出现多线程同时首次引用类的几率变大,通过双重检查锁定等机制进行控制,这将导致系统性能受到影响。
单例模式的优缺点:
优点(1):提供了对唯一实例的受控访问。
(2):在系统内存中只存在一个对象,因此可以节约系统的资源,对于一些需要频繁创建和销毁的对象,使用单例模式无疑是提高了系统的性能。
(3):单例模式允许可变数目的实例。基于单例模式可以进行扩展,使用与控制单例对象相似的方法获得指定个数的实例对象,既节约了系统资源,又解决了由于单例对象共享过多有损性能的问题(自行提供指定数目实例对象的类可成为多例类)
缺点(1):由于单例模式没有抽象层,所以扩展起来很难。
(2):单例类职责过重,在一定程度上违背了单一职责。因为单例类既提供了业务方法,又提供了创建对象的方法(工厂方法),将对象的创建和对象本身的功能耦合在一起。
(3):垃圾回收机制,如果实例化的共享对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源。在下次利用时又将重新实例化,这将导致共享单例对象状态丢失。
单例模式的使用环境:
单例模式作为一种目标明确、结构简单、理解容易的设计模式,在软件开发中使用频率相当高,在很多应用软件和框架中都得以广泛的使用。
在以下情况可以考虑使用单例模式:
1:系统只需要一个实例对象,例如Windows资源管理器,或者因为资源消耗太大而只允许创建一个对象
2:客户调用类单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。
如饥似渴的读着23中设计模式,小弟不才,刚刚接触到设计模式,汗啊-_-||,面向对象,面向对象,面向对象。重要的事情说三遍,接下来洗澡吃饭,回来继续。