Person person1 = new Person();
Person person2 = new Person();
以上代码是我们经常采用了方式,在CLR中,这两行代码做了四件事,在Heap创建了两个引用person1和person2,在Stack中创建两个Person类的实例,也可称为对象。一个对象的任何数据变化或操作都不会影响另一个对象。通常情况下,不会有任何问题。但是,对于独占性强或特殊资源操作的类,就会产生一定的问题。比如:打印机驱动程序。由于打印机是采用串行的工作方式,如果同时有两个信息需要打印机处理,这时打印机便不知道如何处理?为了解决这个问题,我们必须想方法保证在整个系统中保持唯一实例。才能保证打印机正确执行。
保证类有一个且仅有唯一实例,并提供唯一该实例的全局访问点。这就是Singleton的意图(Intent)。
若需实现Singleton,需要解决两个问题:
ü 创建类的实例
创建类的实例都是通过构造器来创建,即使你没有写任何的构造器,编译器也会自动创建一个默认无参构造器,并且该构造器的访问级别为public。因此,只需将默认无参构造器的访问级别为private或protected(可以由子类来创建类的实例)就可以避免由调用者创建类实例,而只能由自身或子类来创建类实例。
ü 全局唯一访问点
全局唯一访问点通常是以属性或者方法来提供。我建议采用方法来获得类实例,感觉这样符合OO的思想(个人见解)。
另外,由于我们在开发过程中经常会使用多线程技术。因此,标准的Singleton实现,需要做进一步的改进。经典的实现方式有饿汉式和懒汉式。但是,这两种方式都是采用伪代码设计出来(这么实现没有任何问题),并没有考虑到各种编译器的机制。
案例说明:
有一个文件和数据同步的需求。客户端会产生一批数据和文件。这批数据和文件需要定时或不这时的上传至服务器或从服务器下载数据和文件。为了避免同一个数据或文件重复上传或下载,不需要对上传或下载操作进行统一管理。我便采用了Singleton模式,以确保统一管理。代码如下:
public class SynchronizerManager
{
/// <summary>
/// 创建唯一类实例
/// 编译器会为由生成一个静态构靠器,解决三个问题:
/// 1、静态构造器在静态字段先被执行,可以确保创建一个类实例。
/// 2、静态构造器可以保证在多线程环境下,只会由一个线程访问,这是由static实现。
/// 3、若不调用GetInstance方法,就不会创建类实例,以实现Lazy Load。
/// </summary>
private static readonly SynchronizerManager instance = new SynchronizerManager();
/// <summary>
/// 确保创建同步管理器只能由类自身来完成。
/// </summary>
private SynchronizerManager()
{
}
/// <summary>
/// 全局唯一访问点
/// </summary>
/// <returns></returns>
public static SynchronizerManager GetInstance()
{
return instance;
}
}
调用事例:
SynchronizerManager synchronizerManager = SynchronizerManager.GetInstance();
设计经验:
l Singleton对于带参构造器的支持不太友好。不过这也不是什么问题,完全可以通过属性或方法来实现。这点点牺牲还是会考。
l 对于是否选择Singleton?通常要从类的职责考虑(前提类的职责清晰),如果是类的本身操作(如:打印机驱动程序、数据同步)需要进行统一管理或者类的内部数据(配置文件,这里很多人采用简单的静态字段来实现,除提升性能之外,并未解决配置文件信息更新的管理,经常会出现配置文件信息在不应该被更新的情况下被更新,导致系统无法正常工作。)必须保持全局唯一性和可管理性,就可以采用Singleton。
Singleton可以扩展成多例模式(如:线程池),机制的实现和Singleton的实现大致相同,只是存在类实例采用集合或数组来存储,这个集合的数量是限定的或者根据应用场景和环境可以更改或设置的,而不是无限扩展,不然就失去对new控制的意义。
Singleton中,通常不用为销毁对象操心,也没有必要,这些销毁的操作都会由垃圾回收器来负责销毁。但是,在多例模式中,特别对于N特别大的时候,通常需要注意通过某种机制来管理已经生成的对象,当然不是实现析构函数来所有已生成的对象销毁,只需在内部根据应用场景和环境适时销毁没有暂时不用的对象,以释放系统资源。
浙公网安备 33010602011771号