java设计模式之——单例模式

来源:互联网 发布:网络歌曲黑名单 编辑:程序博客网 时间:2024/05/23 21:55

转:http://yangguangfu.iteye.com/blog/815944

1,什么是单例模式?

单例模式确保一个类只有一个实例,自行提供这个实例并向整个系统提供这个实例。

 

2,单例模式适合场景?

    单例模式适合于一个类只有一个实例的情况,比如窗口管理器,打印缓冲池和文件系统,它们都是原型的例子。典型的情况是,那些对象的类型被遍及一个软件系统 的不同对象访问,因此需要一个全局的访问指针,这便是众所周知的单例模式的应用。当然这只有在你确信你不再需要任何多于一个的实例的情况下。 
单例模式的用意在于前一段中所关心的。通过单例模式你可以:

 

3,单例模式特点:

 
确保一个类只有一个实例被建立 
提供了一个对对象的全局访问指针 
在不影响单例类的客户端的情况下允许将来有多个实例 。

 

 

4,应用场景举例:

我们举个比较难复制的对象:皇帝

   中国的历史上很少出现两个皇帝并存的时期,是有,但不多,那我们就认为皇帝是个单例模式,在这个场景中,有皇帝,有大臣,大臣是天天要上朝参见皇帝的,今天参拜的皇帝应该是昨天、前天的一样(过渡期的不考虑,别找茬哦),大臣磕完头,抬头一看,嗨,还是昨天那个皇帝,单例模式,绝对的单例模式。

 

先看看类图:

 

然后我们看程序实现,先定义一个皇帝:

Java代码  收藏代码
  1. package com.yangguangfu.singleton;  
  2. /** 
  3.  *  
  4.  * @author 阿福(trygf521@126.com)<br> 
  5.  *中国的历史上都是一个朝代一个皇帝,有两个皇帝的话,必然要PK一个皇帝出来 
  6.  */  
  7. public class Emperor {  
  8.     //定义一个皇帝放在那里,然后给这个皇帝起个名字  
  9.     private static Emperor emperor = null;  
  10.       
  11.     private Emperor(){  
  12.         //世俗和道德的约束你,目的就不让你产生第二个皇帝  
  13.     }  
  14.       
  15.     public static Emperor getInstance(){  
  16.         if(emperor==null){  
  17.             emperor = new Emperor();  
  18.         }  
  19.         return emperor;  
  20.     }  
  21.       
  22.     //皇帝叫什么名字呀  
  23.     public static void emperorInfo(){  
  24.         System.out.println("我是皇帝某某某...阿福");  
  25.     }  
  26.   
  27. }  
 

然后定义大臣

Java代码  收藏代码
  1. package com.yangguangfu.singleton;  
  2.   
  3. public class Minister {  
  4.     public static void main(String[] args) {  
  5.         //第一天  
  6.         Emperor  emperor1 = Emperor.getInstance();  
  7.         //第一天见的皇帝叫什么名字呢?  
  8.         emperor1.emperorInfo();  
  9.           
  10.         //第二天  
  11.         Emperor  emperor2 = Emperor.getInstance();  
  12.         //第二天见的皇帝叫什么名字呢?  
  13.         emperor2.emperorInfo();  
  14.           
  15.         //第三天  
  16.         Emperor  emperor3 = Emperor.getInstance();  
  17.         //第三天见的皇帝叫什么名字呢?  
  18.         emperor3.emperorInfo();  
  19.           
  20.         //三天见的皇帝都是同一个人,荣幸吧,呵呵。  
  21.     }  
  22.   
  23. }  

  看到没,大臣天天见到的都是同一个皇帝,不会产生混乱情况,反正都是一个皇帝,是好是坏就这一个,只要提到皇帝,大家都知道指的的谁,清晰,而又明确。问题是通常情况,还有个例外的,如果同一个时期同一个朝代有两个皇帝,怎么办?

      单例模式很简单,就是在构造函数中多加了一个构造函数,访问权限是private的就可以了,这个模式是简单,但是简单中透着风险,风险?什么风险?在一个B/S项目中,每个HTTP Request请求道J2EE的容器上后都创建了一个线程,每个线程都要创建同一个单例对象,怎么办才好呢?好,我们写一个通用的单例程序,然后分析一下:

 

我们看看皇帝中的:if(emperor==null){ emperor = new Emperor();   }

 我们来看看上面这段代码,假如现在有两个线程A线程和B线程,线程A执行到emperor = new Emperor();,正在申请内存分配,可能需要0.001毫秒,就在这0.001毫秒之内,线程B执行if(emperor==null),你说这个时候判断条件是true还是false?是true,那然后呢?线程B也往下走,于是乎就在内存中就有两个皇帝了,看看是不是出问题了?如果你是个单例去拿一个序列号或者创建一个信号资源的时候,会怎么样?业务逻辑混乱!数据一致性校验失败!最重要的是你从代码上看不出上面问题,这才是要命的!应为有这个情况基本上你是重视不了的,不寒而栗吧,那怎么修改?有多重方案,我就说一种,能简单的、彻底解决问题的方案:

Java代码  收藏代码
  1. package com.yangguangfu.singleton;  
  2. /** 
  3.  *  
  4.  * @author 阿福(trygf521@126.com)<br> 
  5.  *中国的历史上都是一个朝代一个皇帝,有两个皇帝的话,必然要PK一个皇帝出来 
  6.  */  
  7. public class EmperorNew {  
  8.     //定义一个皇帝放在那里,然后给这个皇帝起个名字  
  9.     private static final EmperorNew emperorNew = new EmperorNew();;  
  10.       
  11.     private EmperorNew(){  
  12.         //世俗和道德的约束你,目的就不让你产生第二个皇帝  
  13.     }  
  14.       
  15.     public  synchronized static  EmperorNew getInstance(){  
  16.           
  17.         return emperorNew;  
  18.     }  
  19.       
  20.     //皇帝叫什么名字呀  
  21.     public static void emperorInfo(){  
  22.         System.out.println("我是皇帝某某某...阿福");  
  23.     }  
  24.   
  25. }  
 

直接new一个对象传递给类的成员变量emperorNew,你要的时候getInstance()直接返回给你,问题解决!欧啦!

0 0