第三课 设计模式之Singleton(单态)

第三课 设计模式之Singleton(单态)

 

  单态是我感觉最常用到的设计模式了,所以这里咱们第一个来谈谈他。

  Singleton模式主要作用是保证在应用程序中,一个类Class只有一个实例存在。那么,为什么要这样做呢,这样做有什么好处。下面我们来讨论下。

  首先,很多情况下需要全局的唯一标识,作为一个应用程序的状态之类的作用。

  其次,每个对象的实例化,都需要系统消耗一定的资源,如果全局使用一个对象能够满足要求的话,那么这无疑是节省资源的好方法。特别是像数据库连接这样的对象,多数都用单态来获得。既节省了内存开销,有方便垃圾回收机制回收对象。

下面我们来看看单态的实现方式。

(注意,从这里开始,我贴出的代码可能是C#,的也可能有很多是Java的代码,部分直接引用Java与模式中的代码,重点领会精神)

 

C#

1.          class Singleton { 

2.           public static Singleton Instance() {

3.             if (_instance == null) {

4.             lock (typeof(Singleton)) { 

5.              if (_instance == null) { 

6.               _instance = new Singleton(); 

7.              

8.             

9.            

10.       return _instance; 

11.      

12.       protected Singleton() {

13.      

14.       private static volatile Singleton _instance = null;

15.      

上面这段就是C#实现的一个懒单态模式。(为什么这么称呼别问我,我是这么看到的,估计因为实现太简单)

 

我们来分析下这段代码。

首先它定义了一个静态的对象 _instance

16.       private static volatile Singleton _instance = null;

这里注意,有一个可能很多人没用过的关键字volatile 这个回头我们再解释。

然后有个静态方法 Instance() 返回单态对象。

里面判断 _instance 是否为null,如果为null则实例化他,返回,反之则直接返回 _instance 对象。

这就是基本的懒单态的处理方法。估计大家能够明白怎么保证全局只有一个实例对象的方法了吧。

下面谈谈细节。

首先,volatile关键字的意思是,放弃编译器编译时对代码重新排序,并且放弃优化。这是为什么呢?优化编译器可以将惰性初始化代码优化掉或对其重新进行排序,并且会重新产生线程安全问题。(总之会对多线程同时访问一个对象造成影响)这里的volatile就是声明放弃有话,保证多线程同时访问时值一定相同。

其次,

17.          lock (typeof(Singleton)) { 

这句是否很多人也没有使用过呢。这也是考虑到多线程访问时的安全问题,lock关键字,保证一个线程访问的时候进行锁定,别的线程处于阻塞(及等待状态),知道调用线程对该对象操作完毕。

现在我们这个单态可以说是完善的了,既能够保证全局有且仅有一个实例对象,又能保证其线程安全调用。

下面是java的一个实现。

Java

1.          class Singleton { 

2.           public static Singleton Instance() {

3.             if (_instance == null) {

4.              synchronized (Class.forName("Singleton")) {

5.               if (_instance == null) { 

6.               _instance = new Singleton(); 

7.              

8.             

9.            

10.       return _instance; 

11.      

12.       protected Singleton() {

13.      

14.       private static Singleton _instance = null

15.      

貌似现在Java也有volatile 但是我没应用过,大家可以尝试一下。Java中线程会有一个共享对象的copy保存,所以这里用synchronized,目的是同步线程间的copy,作用同lock差不多,不过感觉不如lock保险(个人意见)。

这种LazySingleton 懒单态是最常见的。其实不牵扯到多线程的话,完全可以将volatileLock省略.

18.       class Singleton { 

19.        public static Singleton Instance() {

20.          if (_instance == null) {

21.          _instance = new Singleton(); 

22.         

23.        

24.       return _instance; 

25.      

26.       protected Singleton() {

27.      

28.       private static  Singleton _instance = null;

29.      

这样调用足够了。

其实单态还有一些复杂的设计方式,下面引用一段《java与模式》中的代码

Java

1.          package com.javapatterns.singleton.demos;

2.           

3.           

4.          import java.util.HashMap;

5.           

6.          public class RegSingleton {

7.           

8.              protected RegSingleton() {}

9.           

10.           static public RegSingleton getInstance(String name)

11.           {

12.               if (name == null)

13.               {

14.                   name = "com.javapatterns.singleton.demos.RegSingleton";

15.               }

16.        

17.               System.out.println("From RegSingleton: requesting for " + name );

18.        

19.               if (m_registry.get(name) == null)

20.               {

21.                   try

22.                   {

23.                       m_registry.put( name, Class.forName(name).newInstance() ) ;

24.                   }

25.                   catch(ClassNotFoundException e)

26.                   {

27.                       System.out.println("Class " + name + " is not found.");

28.                   }

29.                   catch(InstantiationException e)

30.                   {

31.                       System.out.println("Class " + name + " can not be instantiated.");

32.                   }

33.                   catch(IllegalAccessException e)

34.                   {

35.                       System.out.println("Class " + name + " can not be accessed.");

36.                   }

37.               }

38.               return  (RegSingleton) (m_registry.get(name) );

39.           }

40.        

41.           static private HashMap m_registry = new HashMap();

42.        

43.           /**

44.            * @label Creates

45.            * @directed*/

46.           /*# private RegSingletonChild lnkRegSingletonChild; */

47.        

48.           /**

49.            * @label Creates

50.            * @directed

51.            */

52.           /*# private RegSingleton lnkRegSingleton;  */

53.        

54.           static

55.           {

56.               RegSingleton x = new RegSingleton();

57.               m_registry.put( x.getClass().getName() , x);

58.           }

59.        

60.           public String about()

61.           {

62.               return "Hello, I am RegSingleton.";

63.           }

64.        

65.       }

66.        

 

  1. package com.javapatterns.singleton.demos;
  2. /**
  3.  * This class is a subclass of RegSingleton
  4.  */
  5. import java.util.HashMap;
  6. public class RegSingletonChild extends RegSingleton
  7. {
  8.     public RegSingletonChild() {}
  9.     static public RegSingletonChild getInstance()
  10.     {
  11.         return (RegSingletonChild) RegSingleton.getInstance( "com.javapatterns.singleton.demos.RegSingletonChild" );
  12.     }
  13.     public String about()
  14.     {
  15.         return "Hello, I am RegSingletonChild.";
  16.     }
  17. }

 

  1. package com.javapatterns.singleton.demos;
  2. public class RegSingletonTest
  3. {
  4.     public static void main(String[] args)
  5.     {
  6.         //(1) Test eager
  7.         //System.out.println( EagerSingleton.getInstance() );
  8.         //RegSingletonTest test = new RegSingletonTest();
  9.         System.out.println( RegSingleton.getInstance("com.javapatterns.singleton.demos.RegSingleton").about() )   ;
  10.         System.out.println( RegSingleton.getInstance(null).about() )   ;
  11.         System.out.println( RegSingleton.getInstance("com.javapatterns.singleton.demos.RegSingletonChild").about() )   ;
  12.         System.out.println( RegSingletonChild.getInstance().about())   ;
  13.     }
  14. }

子类要实例话需要依靠父类,是为什么呢,自己体会吧。

本次单态课程结束。下节课讲工厂模式吧。

 

作者:王文斌

转载请注明出处。

你可能感兴趣的:(java,设计模式,多线程,null,Class,编译器)