设计模式(4)单例模式(讲解+应用)

目录

  1. 单例模式

  2. 为什么使用单例模式

  3. 单例模式实际应用

单例模式

这个设计模式应该算是我最早接触到一个,也是从那个时候知道有一种东西叫设计模式,看到这种代码结构,有种将好的东西通过某种精美的包装进行包装一样,似锦上添花。

单例模式:单例模式中有一个单例类的结构,来保证系统中,该类只能够被实例化一个,通过这种方式控制系统中实例的个数,同时易于外界访问。

为什么使用单例模式

对于缓存,数据库连接,网络请求队列等,资源消耗比较大的,通常我们只是需要一个实例,来减少资源的消耗。
为什么不实用静态全局变量来进行控制呢?
通过静态全局变量持有一个我们创建的实例,然后对这个实例进行一些操作不也是可以保证单例吗?这种方式似乎要比多出一个设计模式去改变类的结构方便的多,但是我们却不会这样去做,原因就是

  1. 当我们设置一个全局的变量在系统中,其会导致出现命名空间污染现象,导致我们在一些引用的过程中,出现了将全局变量作为局部变量使用的情况,

  2. 同时如果我们对于静态全局变量如果不加锁的话,很容易在多线程操作的过程中带来同步上的一些问题,

  3. 最后一个原因就是如果我们将其作为一个静态全局变量使用,那么我们就无法实现一个惰性创建实例,对于过于消耗资源的实例,通过惰性创建,我们将其拖延至使用时创建,而不会过早的消耗资源。

单例模式的实际应用

到了看一下单例模式庐山真面目的时候了,首先通过一段简单的Java代码看一下其大体结构。

public class Singleton{
    private static Singleton mSingleton = null;
    private Singleton(){

    }
    public static Singleton getInstance(){
        if(mSingleton==null)
            mSingleton = new Singleton();
        return mSingleton;
    }
}

上面是一个简单单例模式的示范代码,通过这个代码,我们可以看出单例类的构造方法是私有方法,也就是该类我们没有办法通过new得到的,只能够通过静态的getInstance()方法得到。但是对于多线程问题,如果有多个线程在执行这个方法,那么可能就会有多个实例被创建出来,如何应对这个问题呢?

1.对该代码区域进行同步

public class Singleton{
    private static Singleton mSingleton = null;
    private Singleton(){
    }
    public synchronized Singleton static getInstance(){
        if(mSingleton==null)
            mSingleton = new Singleton();
        return mSingleton;
    }
}

当我们对代码块进行加锁之后,一个线程就要等到另一个线程结束之后,才可以继续执行该区域代码,但是当我们对一个代码区域进行加锁之后,我们的代码效率就会降低100倍。对这个代码区域进行同步之后,每当我们执行这块代码,都将会出现一个等待。
2.急切创建实例,而不是采用惰性创建

public class Singleton{
    private static Singleton mSingleton = new Singleton();
    private Singleton(){

    }
    public synchronized Singleton static getInstance(){
        return mSingleton;
    }
}

通过急切创建在对类进行初始化的时候就实例化了类,就不会出现多个线程竞争的问题,但是会导致的问题是如果创建实例消耗过大的时候就会出现提前消耗资源的问题。因此我们常采用的一种方法是双重加锁法。
3.双重检查加锁

public class Singleton{
    private static Singleton mSingleton = null;
    private Singleton(){

    }
    public Singleton static getInstance(){
        if(mSingleton==null){
            synchronized (Singleton.class){
                if(mSingleton==null)
                    mSingleton = new Singleton();
            }
        }
        return mSingleton;
    }
}

这种方式对于加锁不是对整个方法进行加锁,而是判断当这个单例未被初始化之后,才对这个实例的初始化区域进行一个同步,在同步的过程中在进行一个是否实例化的判断。即所谓的双重检查。课有疑问的在于,我们已经进入了同步区域了,为什么还要对其做一个判断呢?就是当两个线程同时越过了第一个判断之后,如果我们在同步方法中没有对与实例的判断,这个时候,我们就有可能出现实例被创建两次的情况。
综上所述:综合效率,资源消耗等来看,通过双重检查加锁的方式来创建最为方便。
单例模式在android中有那些应用呢?
android中有很多系统级别的全局变量,如时间,输入法,账户,状态栏等等
InputMethodManager类,CalendarDatabaseHelper类、Editable类等等。在这些类中,都存在一个方法getInstance,在该方法或直接返回对象的引用或判断一个类的引用是否为NULL,若不为NULL,则直接返回该引用,若为NULL,则new一个新的对象,并返回。例如,对于CalendarDatabaseHelper类,存在如下的代码:

public static synchronized CalendarDatabaseHelper getInstance(Contextcontext)  
{  
    if (sSingleton == null)  
    {  
       sSingleton = newCalendarDatabaseHelper(context);  
    }  
        return sSingleton;  
}  

下一篇文章将更新关于装饰器设计模式相关的

    原文作者:设计模式
    原文地址: https://segmentfault.com/a/1190000003793726
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞