论坛首页 入门技术论坛

java设计模式全解[1]-单例模式

浏览 13299 次
该帖已经被评为新手帖
作者 正文
   发表时间:2007-06-10  

在网上找了很久都没有找到详细分析java 设计模式的 后来在网上找到个.net的 看了后决定 对C#的代码进行java本地化(借用下这个词,不知道把C#变java叫做什么) 不敢独享 拿来与大家分析,当作搬家到javaeye 后zmo_xu给大家的见面礼吧,还请各位高手不要耻笑区区在下(文章有自己的理解也有网上原文,如果你发现zmo_xu个文章里面设计到了你的文章的版权 敬请致电 zmo2xu@gmail.com 我会及时处理),好了言归正传

第1章 单件模式(Single Pattern)

概述



    Singleton模式要求一个类有且仅有一个实例,并且提供了一个全局的访问点。这就提出了一个问题:如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?客户程序在调用某一个类时,它是不会考虑这个类是否只能有一个实例等问题的,所以,这应该是类设计者的责任,而不是类使用者的责任。
从另一个角度来说,Singleton模式其实也是一种职责型模式。因为我们创建了一个对象,这个对象扮演了独一无二的角色,在这个单独的对象实例中,它集中了它所属类的所有权力,同时它也肩负了行使这种权力的职责!


意图

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

生活中的例子


美国总统的职位是Singleton,美国宪法规定了总统的选举,任期以及继任的顺序。这样,在任何时刻只能由一个现任的总统。无论现任总统的身份为何,其头衔"美利坚合众国总统"是访问这个职位的人的一个全局的访问点。

简单实现:最简单的实现就是在类内声明一个此类的实例并将构造函数私有化(为什么要用private而不用protected来保持可扩展性是因为 当类被继承后影响单例模式) 并向外公开一个getInstance()方法来获取这个实例集体实现 集体实现

java 代码
  1. package unit;   
  2.   
  3. public class Singletnon   
  4. {   
  5.  private static  Singletnon instance;   
  6.     
  7.  private Singletnon()   
  8.  {   
  9.      
  10.  }   
  11.  public static Singletnon getInstance()   
  12.  {   
  13.   if(instance==null)   
  14.   {   
  15.    instance=new Singletnon();   
  16.   }   
  17.   return instance;   
  18.  }   
  19. }   


大家可以看到这里的构造方法

 

是私有的,类外是无法访问的,就是说实现了限制实例化,但是一个类如果没有办法实例化那么这个类将什么也作不了 所以在这个类里面就的提供一个方法来实现实例化 也就是这里的getInstance将在类内对自己实例化并将实例传递出去,好了到此我们已经理解单例模式的实现,那么我们就要考虑安全问题 还有我们是不是真的实现了单例,其实这种模式在多线程模式下是不一定能实现单例模式的稍后我会在后面用一个例子来证明他,现在我们来考虑线程安全,你说synchronized ?,非常好 你已经抓住了问题的关键,我们接着往下走,修改后我们的代码变成了这样

  1. package unit;   
  2.   
  3. public class Singletnon   
  4. {   
  5.  private static Singletnon instance;   
  6.     
  7.  private Singletnon()   
  8.  {   
  9.      
  10.  }   
  11.  public synchronized static Singletnon getInstance()   
  12.  {   
  13.   if(instance==null)   
  14.   {   
  15.    instance=new Singletnon();   
  16.   }   
  17.   return instance;   
  18.  }   
  19. }   

 

这里这个方法已经线程安全了但是我们知道对一个方法进行线程安全资源消耗是非常大的我们更倾向于对代码的同步 修改后的代码
java 代码
  1. package unit;   
  2.   
  3. public class Singletnon   
  4. {   
  5.     private static Singletnon instance;   
  6.   
  7.     private static final Object key = new Object();   
  8.   
  9.     private Singletnon()   
  10.     {   
  11.   
  12.     }   
  13.   
  14.     public static Singletnon getInstance()   
  15.     {   
  16.         if (instance == null)   
  17.         {   
  18.             synchronized (key)   
  19.             {   
  20.                 if (instance == null)   
  21.                 {   
  22.                     instance = new Singletnon();   
  23.                 }   
  24.             }   
  25.         }   
  26.         return instance;   
  27.     }   
  28. }   

可以看到 zmo_xu在这里引入了一个Object 的对象key 为什么要引入一个key呢 用instance作为同步关键字不是更好吗!这个当然不行,因为线程同步锁锁定的是地址引用 如果你锁定的是instance的化 当你new的时候 地址引用就会改变.线程锁失效,额你说什么 不new 行不行..不new   不new.....不牛,我只能说这些想的人太牛了,要知道我们这里要保护的代码就是为了实例化,我们一定要牛(new)的拉!

单例模式就说到这里 下一次我们将介绍抽象工厂!

javastudy给出的代码补充在这里 !基本上思路是一样的 只是代码实现上有点区别

  1. //饿汉式:    
  2. public class EagerSingleton {    
  3. private EagerSingleton() { }   
  4.   
  5. public static EagerSingleton getInstance() {    
  6. return m_instance;    
  7. }   
  8.   
  9. /** @label Creates */    
  10. private static final EagerSingleton m_instance = new EagerSingleton();    
  11. }    

 

java 代码
    //懒汉式
  1. public class LazySingleton    
  2. {    
  3. private LazySingleton() { }   
  4.   
  5. synchronized public static LazySingleton getInstance()    
  6. {    
  7.    if (m_instance == null)    
  8.    {    
  9.        m_instance = new LazySingleton();    
  10.    }    
  11.    return m_instance;    
  12.   }   
  13. }
  14. //使用到才实例化 不使用不实例化,比如你使用此类的其他静态方法 而饿汉式只要用到就被实例化
java 代码
  1. //登记式:      
  2.      
  3. import java.util.HashMap;       
  4. public class RegSingletonChild extends RegSingleton       
  5. {       
  6. public RegSingletonChild() {}      
  7.      
  8. static public RegSingletonChild getInstance()       
  9. {       
  10. return (RegSingletonChild) RegSingleton.getInstance( "com.javapatterns.singleton.demos.RegSingletonChild" );       
  11. }      
  12.      
  13. public String about()       
  14. {       
  15. return "Hello, I am RegSingletonChild.";       
  16. }      
  17.      
  18. }      
  19. //这个 嘿嘿 不太明白 待会去看看他的父类原代码     

这个帖子的代码部分不会再修改了 就此代码部分封帖 ,希望大家 一起继续讨论共同提高

最后附上所有原代码

  • Singleton.rar (4.9 KB)
  • 描述: 单例模式的测试代码
  • 下载次数: 166
   发表时间:2007-06-10  
莫名的提交失败,受不了,我只能修改点提交再修改,有点受不了的说
0 请登录后投票
   发表时间:2007-06-10  

 

这里这个方法已经线程安全了但是我们知道对一个方法进行线程安全资源消耗是非常大的我们更倾向于对代码的同步 修改后的代码
java 代码
  1. package unit;   
  2.   
  3. public class Singletnon   
  4. {   
  5.     private static Singletnon instance;   
  6.   
  7.     private static final Object key = new Object();   
  8.   
  9.     private Singletnon()   
  10.     {   
  11.   
  12.     }   
  13.   
  14.     public synchronized static Singletnon getInstance()   
  15.     {   
  16.         if (instance == null)   
  17.         {   
  18.             synchronized (key)   
  19.             {   
  20.                 if (instance == null)   
  21.                 {   
  22.                     instance = new Singletnon();   
  23.                 }   
  24.             }   
  25.         }   
  26.         return instance;   
  27.     }   
  28. }   



话说用了两个synchronized同步性能就会提高么?

感觉里面那个synchronized (key) 有画蛇添足之嫌.

关于 Singleton 的线程安全问题,Effective JAVA里面已经讲的很清楚,可以用initialize-on-demand holder class:

java 代码
  1. public class  Singleton {   
  2.   
  3.          private static class  SingletonHandler{   
  4.   
  5.                       static final  Singleton  singleton =new  Singleton();    
  6.   
  7.          }   
  8.   
  9.          private  Singleton (){}   
  10.   
  11.          public static  Singleton getInstance(){   
  12.   
  13.                     return SingletonHandler.singleton;   
  14.   
  15.          }   
  16.   
  17. }   




0 请登录后投票
   发表时间:2007-06-10  
不错,学习中,希望楼主继续,能够学到更多的模式,
也欢迎高手,指出其中的不足,大家一起讨论会更好
0 请登录后投票
   发表时间:2007-06-10  
三种?你是说?能说一下什么意思吗是关系到安全性什么的还是实现上的.我这里并没有说我这里给出了所有的方式,我只是给出了几个经典的常用模式,而且我也还不知道怎么实现延期实例化的实现,望高手赐教
0 请登录后投票
   发表时间:2007-06-11  
学习中,希望持续进行!并且能给点好的实例
0 请登录后投票
   发表时间:2007-06-11  
javastudy 写道
zmo_xu 写道
三种?你是说?能说一下什么意思吗是关系到安全性什么的还是实现上的.我这里并没有说我这里给出了所有的方式,我只是给出了几个经典的常用模式,而且我也还不知道怎么实现延期实例化的实现,望高手赐教


懒汉式,饿汉式,登记式

.......

到底是什么啦,说清楚点,最好像楼主那样把相应的代码贴出来,谢谢!
0 请登录后投票
   发表时间:2007-06-11  
谁给个三种实现方式的链接
0 请登录后投票
   发表时间:2007-06-11  
javastudy 你的懒汉式的和我上面的是一样的啊 我的只是里面加入了线程安全在方法的内部  而你是加载在整个方法上
另外顺便把你的代码引用到我的帖子里面去了
0 请登录后投票
   发表时间:2007-06-12  
hao dongxi
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics