你的位置:首页 > ASP.net教程

[ASP.net教程]设计模式(一)__单例设计模式


先来介绍一下什么是设计模式,设计模式起先是从建筑行业借鉴来的,然后慢慢发展到了今天这个样子。

设计模式是解决问题最行之有效的思想,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

java有23种设计模式,今天就先来介绍一种:单例设计模式

单例设计模式:

  有时候当你需要保证一个类在内存中的对象唯一性的时候,比如多程序读取一个配置文件时,建议配置文件封装成对象。会方便操作其中数据,又要保证多个程序读到的是同一个配置文件对象,就需要该配置文件对象在内存中是唯一的。那么这时候你就需要用到单例设计模式了。

  那么,如何保证对象的唯一性呢?

    思想:

    1. 不让其他类创建该类对象。
    2. 在本类中创建一个本类对象
    3. 对外提供方法,让其他程序获取这个对象

    步骤:

      1. 因为创建对象都需要构造函数初始化,所以只需要将本类中的构造函数私有化,这样其他类就不能创建该类对象了。

      2. 在本类中创建一个本类对象

      3. 定义一个公有方法,返回该对象,让其他类访问。(作用:可控) 

好了,上面就把单例模式的思路给大家说了下,单例模式的写法有好几种,这里主要介绍两种:懒汉式单例、饿汉式单例。

一:饿汉式

class Single {  private Single() {} // 私有化构造函数。  private static final Single s = new Single(); // 创建私有并静态的本类对象。  public static Single getInstance() { // 定义公有并静态的方法,返回该对象。    return s;  }}

饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

二:懒汉式

class Single {  private Single() {}  private static Single s = null;  public static Single getInstance() {    if (s == null)      s = new Single();    return s;  }}

但是以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Single实例,要实现线程安全,可通过多判断加同步来解决。

class Single {  private Single() {};  private static Single s = null;  public static Single getInstance() {    if (s == null) {      synchronized (Single.class) {        if (s == null) {          s = new Single();        }      }    }    return s;  }}

--------------------------------------------------------------------------------------------

双重锁检查只能在jdk1.5以后才能有效,1.5以前在java对象模型中的无序写问题不能保证。

查阅了一下资料,发现还可以通过静态内部类来解决延迟加载的安全问题。

class Single {  private Single() {};  private static class Holder {    private static final Single INSTANCE = new Single();  }  public static Single getInstance() {    return Holder.INSTANCE;  }}

这种方式既实现了线程安全,又避免了同步带来的性能影响

那么为什么这样可以实现单例呢?

先来介绍一下内部类:

内部类分为对象级别和类级别,类级内部类指的是,有static修饰的成员变量的内部类。如果没有static修饰的成员变量的内部类被称为对象级内部类。

类级内部类相当于其外部类的static成员,它的对象与外部类对象间不存在依赖关系,相互独立,因此可直接创建。而对象级内部类的实例,是必须绑定在外部对象实例上的。类级内部类只有在第一次被使用的时候才被会装载。

当getInstance方法第一次被调用的时候,它第一次读取Holder.instance,内部类Holder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Single的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。

这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。

个人推荐此种方式。

--------------------------------------------------------------------------------------------

三:饿汉式和懒汉式区别

饿汉比较急,类一旦加载,就把单例初始化完成。

懒汉太懒了,只有当调用getInstance的时候,才会去初始化这个单例。

饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题。

懒汉式本身是非线程安全的。

饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成。

而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,而且因为线程安全问题,需要加同步,效率上比较低。

总之,从速度和反应时间角度来讲,饿汉式好;从资源利用效率上说,延迟加载(又称懒汉式)好。