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

来源:互联网 发布:现代四大名著网络 编辑:程序博客网 时间:2024/06/05 23:59

        俺有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("美男子可以和亲爱的妻子约会了!");}}





0 0
原创粉丝点击