创建型模式:单例模式(SINGLETON)

转载地址:http://blog.csdn.net/lingyun_blog/article/details/41518145

俺有6个漂亮的老婆,她们的老公都是我,我就是我们家里的老公Singleton,她们只要说道“老公”,都是指的同一个人,那就是我(刚才做了个梦啦,哪有这么好的事)


定义  
        有单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的“单一实例”的需求时才可使用。



使用场景

        当类只能有一个实例而且第三方可以从一个公共的访问点访问它时。
        当一个唯一的实例可以通过子类化来扩展,而且第三方需要在不更改代码的情况下就能使用一个扩展的实例时。
        

优缺点分析
优点:
1.实例控制        
        对唯一的实例做出访问控制。
        允许改变实例的数目,事实上单例模式只是实例有限的类的一种特列,通过计数等方式可以做到双例模式,三例模式等需要实例化有限次的类。
2.灵活性
        因为类控制了实例化过程,所以类可以灵活更改实例化过程。
缺点:
1.开销
       虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
2.可能的开发混淆
       使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
3.对象生存期
       不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。


单例模式UML图




应用场景及代码分析
        在开头的时候提到梦中的时候梦到了自己有好多的老婆,有中国的老婆、有美国的老婆…(ps:在我们伟大的天朝里,可是施行一夫一妻、男女平等的婚姻制度)。为了给大家演示单例模式,我们假设有2个老婆,一个中国的老婆、一个美国的老婆,老公只有一个,老公要时常的陪妻子约会,妻子觉得单独和老公出去才是浪漫,所以她们都想老公只带自己出去约会。
       首先我们先看一下老公的类,因为老公只有一个,所以老公我们使用单例模式创建,如下代码:

//单例,老公类
public class Husband {

    //老公只有一个
    private static Husband instance;

    private Husband() {
    }

    public static Husband getInstance() {
        if (instance == null) {
            instance = new Husband();
        }
        return instance;
    }

    public void show(){
        System.out.println("老公可是一个安静的美男子!");
    }
    
    public void date(){
        System.out.println("美男子可以和亲爱的妻子约会了!");
    }
}


两个老婆分别有找老公和约会的方法
//中国妻子类
public class ChinaWife {
    
    private Husband myHusband = null;
    
    //找老公
    public void showHusband(){
        myHusband = Husband.getInstance();
        myHusband.show();
    }

    //和老公约会
    public void dateWithHusband(){
        myHusband = Husband.getInstance();
        myHusband.date();
    }
}

//美国妻子
public class AmericanWife {

    private Husband myHusband = null;
    
    //找老公
    public void showHusband(){
        myHusband = Husband.getInstance();
        myHusband.show();
    }

    //和老公约会
    public void dateWithHusband(){
        myHusband = Husband.getInstance();
        myHusband.date();
    }
}

实现了老公和妻子的代码以后,我们要开始测试了:
public class SingletonTest {
    
    public static void main(String[] args){
        AmericanWife amWife = new AmericanWife();
        System.out.println("美国妻子:我要找老公!");
        amWife.showHusband();
        System.out.println("美国妻子:老公和我约会吧!");
        amWife.dateWithHusband();
        
        ChinaWife chWife = new ChinaWife();
        System.out.println("中国妻子:我要找老公!");
        chWife.showHusband();
        System.out.println("中国妻子:老公和我约会吧!");
        chWife.dateWithHusband();
    }
}

结果如下:
美国妻子:我要找老公!
老公可是一个安静的美男子!
美国妻子:老公和我约会吧!
美男子可以和亲爱的妻子约会了!
中国妻子:我要找老公!
老公可是一个安静的美男子!
中国妻子:老公和我约会吧!
美男子可以和亲爱的妻子约会了!


        我们可以看到当两个妻子都能找到老公,老公是同一个人,而且都和老公约会了。
        有一天,美国老婆希望老公和她出去约会,他心情愉悦,可是在他准备好好打扮自己的时候,中国妻子开开心心的跑了过来,“老公,和奴家约会去呗!”,这可怎么办啊,老公可没有韦小宝那么机灵,答应了美国老婆,可又不想让中国老婆失望,他陷入了思考之中!
        在我们的老公的实例创建方法中,
if (instance == null) {
instance = new Husband();
}
        美国老婆申请了老公实例,这时候老公实例还没有创建,所以instance ==null,那么老公会创建出一个实例来,可是还没等老公创建出实例,中国老婆也过来申请老公了,这时候老公还是没有创建出来,所以instance还是null,老公还会创建出来,这样就创建出了2个老公实例,可老公明明就是1个啊。在我们的代码中,如果有多个线程同时访问老公创建实例的方法,就不满足我们单例模式的单例了。
我们需要为实例过程加锁,修改老公类:

//单例,老公类
public class Husband {

    static Lock lock = new ReentrantLock();

    // 老公只有一个
    private static Husband instance;

    private Husband() {
    }

    public static Husband getInstance() {
        //这里判断是为了防止频繁的进行加解锁
        if (instance == null) {
            //加上锁
            lock.lock();
            //创建实例,并且能够防止多次创建实例
            if (instance == null) {
                instance = new Husband();
            }
            //解锁
            lock.unlock();
        }
        return instance;
    }

    public void show() {
        System.out.println("老公可是一个安静的美男子!");
    }

    public void date() {
        System.out.println("美男子可以和亲爱的妻子约会了!");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值