大话设计模式--Singleton(单例模式)
——Angel
目录
说明:
1> 开发工具Eclipse
2> 开发平台Window Xp
3> 有问题可联系本人 QQ:412887952
1.什么是Singleton – 单例模式
我有6个漂亮的老婆,她们的老公都是我,我就是我们家的singleton,她们只要说道”老公”,都是指同一个人,那就是我。
(哎,哪有那么好的事呀,除非做梦了。)
笑够了就得回来了。我们的目标还是学习,当然咱们学习讲究乐中学,学中乐,最终是快乐成长。我们回头看看这个笑话:
【我】就是程序中的一个【类】
【我的6个老婆】就是程序中的“我”的6个实例。(平时我们都是用new 实例化对象,当然用这种方式构造出来的对象,那就不是我同一个对象了,回到例子的话,也就是说,我的6个漂亮老婆就不是我了,是其他对应的6个人了,嘎嘎,啊啊,我不要这样呀,我要我的老婆呀。)
【同一个人,都是我】就是程序用的同一个对象,从内存来看的话就是地址相等。(等下我们用程序证明:我们获取的对象都是同一个对象。)
从上面可以看出所谓的单例:就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
更多资料:http://baike.baidu.com/view/1859857.htm
2. 非Singleton例子
在学习Singleton模式之前,我们先看看以前普通的java类。
现在让我们一起创建一个 “我的类”,类名为Angel (这个是我的QQ昵称,所以这么命名呀。),在此类中提供一个方法,比如 loveMyWife (“我爱我的6个老婆“)
Angel.java代码如下:
package singleton_001;
/**
* 自己的一个类
* @author Administrator
*
*/
public class Angel {
public void loveMyWife(){
System.out.println("我爱我的老婆,我的6个老婆都是我的呀,不允许公用!");
}
}
说明:这个类没有太多的知识点,仅是普普通通的一个类,类中有一个简单的方法,方法中输出一句话。
我们在写一个测试类,来测试我们的程序,类名为 TestAngel.java
TestAngel.java代码如下:
package singleton_001;
public class TestAngel {
/** main方法启动程序*/
public static void main(String[] args) {
Angel myWife = new Angel();//假设这个是真正的老婆
Angel myWife1 = new Angel();// 我的第一个老婆
Angel myWife2 = new Angel();// 我的第二个老婆
Angel myWife3 = new Angel();// 我的第三个老婆
Angel myWife4 = new Angel();// 我的第四个老婆
Angel myWife5 = new Angel();// 我的第五个老婆
Angel myWife6 = new Angel();// 我的第六个老婆
/*我们通过比较对象的对象是否相同,来判定是否同一个实例*/
if(myWife == myWife1){//相等的时候
System.out.println("老婆1说:老公我爱你,你永远是我的好老公");
System.out.println("我说:都是我的好老婆....");
}else {//不相等的时候
System.out.println("老婆1说:你不是我的老公,走开了呀!");
System.out.println("我说:啊,不要,我要你做我的老婆");
}
if(myWife == myWife2){//相等的时候
System.out.println("老婆2说:老公我爱你,你永远是我的好老公");
System.out.println("我说:都是我的好老婆....");
}else {//不相等的时候
System.out.println("老婆2说:你不是我的老公,走开了呀!");
System.out.println("我说:啊,不要,我要你做我的老婆");
}
if(myWife == myWife3){//相等的时候
System.out.println("老婆3说:老公我爱你,你永远是我的好老公");
System.out.println("我说:都是我的好老婆....");
}else {//不相等的时候
System.out.println("老婆3说:你不是我的老公,走开了呀!");
System.out.println("我说:啊,不要,我要你做我的老婆");
}
if(myWife == myWife4){//相等的时候
System.out.println("老婆4说:老公我爱你,你永远是我的好老公");
System.out.println("我说:都是我的好老婆....");
}else {//不相等的时候
System.out.println("老婆4说:你不是我的老公,走开了呀!");
System.out.println("我说:啊,不要,我要你做我的老婆");
}
if(myWife == myWife5){//相等的时候
System.out.println("老婆5说:老公我爱你,你永远是我的好老公");
System.out.println("我说:都是我的好老婆....");
}else {//不相等的时候
System.out.println("老婆5说:你不是我的老公,走开了呀!");
System.out.println("我说:啊,不要,我要你做我的老婆");
}
if(myWife == myWife6){//相等的时候
System.out.println("老婆6说:老公我爱你,你永远是我的好老公");
System.out.println("我说:都是我的好老婆....");
}else {//不相等的时候
System.out.println("老婆6说:你不是我的老公,走开了呀!");
System.out.println("我说:啊,不要,我要你做我的老婆");
}
}
}
说明:这个类看是代码特别多,但是提取出重要代码的话,就一句话:
new if (初始化对象,判断对象是否是同一个对象。)
运行代码,结果如下:
老婆1说:你不是我的老公,走开了呀!
我说:啊,不要,我要你做我的老婆
老婆2说:你不是我的老公,走开了呀!
我说:啊,不要,我要你做我的老婆
老婆3说:你不是我的老公,走开了呀!
我说:啊,不要,我要你做我的老婆
老婆4说:你不是我的老公,走开了呀!
我说:啊,不要,我要你做我的老婆
老婆5说:你不是我的老公,走开了呀!
我说:啊,不要,我要你做我的老婆
老婆6说:你不是我的老公,走开了呀!
我说:啊,不要,我要你做我的老婆
结果分析:
通过代码我们发现,这种方式的对象都是不相等的。(嘎嘎,没有一个是我的老婆呀,不做我老婆做我小妾也可以呀。)
接下来我们看看单例的例子。我们来修改下我们之前的代码.
观察我们的代码,我们发现我们的每一个实例都是通过new的方式进行生产的,我们知道通过new产生的对象就会在计算机内存开辟一个内存空间,所以肯定不是同一个对象。现在我们要让实例化的对象都是一样的,也就是说这个对象的产生,我们自己控制,不允许他人用new的方式进行构造,所以第一步我们需要把无参构造方法给屏蔽掉,也就是重写无参构造方法,将该方法改成私有的。改完之后,我们会发现我们根本就得不到我们的实例,那怎么办呢,我们通过一个静态方法来构造对象。代码体现如下:
Angel.java代码:
package singleton_002;
/**
* 自己的一个类
* @author Administrator
*
*/
public class Angel {
/*该类对象,用静态变量,确保只在内存开辟一个内存空间*/
private static Angel instance;
/**将该类的构造方法屏蔽*/
private Angel(){};
/**提供获取该类的实例*/
public static Angel getInstance(){
if(instance == null){
synchronized (Angel.class) {//锁住当前类,防止两个线程同时访问
instance = new Angel();
}
}
return instance;
}
public void loveMyWife(){
System.out.println("我爱我的老婆,我的6个老婆都是我的呀,不允许公用!");
}
}
TestAngel.java代码:
package singleton_002;
import java.io.ObjectInputStream.GetField;
public class TestAngel {
/** main方法启动程序*/
public static void main(String[] args) {
Angel myWife = Angel.getInstance();//假设这个是真正的老婆
Angel myWife1 = Angel.getInstance();// 我的第一个老婆
Angel myWife2 = Angel.getInstance();// 我的第二个老婆
Angel myWife3 = Angel.getInstance();// 我的第三个老婆
Angel myWife4 = Angel.getInstance();// 我的第四个老婆
Angel myWife5 = Angel.getInstance();// 我的第五个老婆
Angel myWife6 = Angel.getInstance();// 我的第六个老婆
/*我们通过比较对象的对象是否相同,来判定是否同一个实例*/
if(myWife == myWife1){//相等的时候
System.out.println("老婆1说:老公我爱你,你永远是我的好老公");
System.out.println("我说:都是我的好老婆....");
}else {//不相等的时候
System.out.println("老婆1说:你不是我的老公,走开了呀!");
System.out.println("我说:啊,不要,我要你做我的老婆");
}
if(myWife == myWife2){//相等的时候
System.out.println("老婆2说:老公我爱你,你永远是我的好老公");
System.out.println("我说:都是我的好老婆....");
}else {//不相等的时候
System.out.println("老婆2说:你不是我的老公,走开了呀!");
System.out.println("我说:啊,不要,我要你做我的老婆");
}
if(myWife == myWife3){//相等的时候
System.out.println("老婆3说:老公我爱你,你永远是我的好老公");
System.out.println("我说:都是我的好老婆....");
}else {//不相等的时候
System.out.println("老婆3说:你不是我的老公,走开了呀!");
System.out.println("我说:啊,不要,我要你做我的老婆");
}
if(myWife == myWife4){//相等的时候
System.out.println("老婆4说:老公我爱你,你永远是我的好老公");
System.out.println("我说:都是我的好老婆....");
}else {//不相等的时候
System.out.println("老婆4说:你不是我的老公,走开了呀!");
System.out.println("我说:啊,不要,我要你做我的老婆");
}
if(myWife == myWife5){//相等的时候
System.out.println("老婆5说:老公我爱你,你永远是我的好老公");
System.out.println("我说:都是我的好老婆....");
}else {//不相等的时候
System.out.println("老婆5说:你不是我的老公,走开了呀!");
System.out.println("我说:啊,不要,我要你做我的老婆");
}
if(myWife == myWife6){//相等的时候
System.out.println("老婆6说:老公我爱你,你永远是我的好老公");
System.out.println("我说:都是我的好老婆....");
}else {//不相等的时候
System.out.println("老婆6说:你不是我的老公,走开了呀!");
System.out.println("我说:啊,不要,我要你做我的老婆");
}
}
}
运行代码结果如下:
老婆1说:老公我爱你,你永远是我的好老公
我说:都是我的好老婆....
老婆2说:老公我爱你,你永远是我的好老公
我说:都是我的好老婆....
老婆3说:老公我爱你,你永远是我的好老公
我说:都是我的好老婆....
老婆4说:老公我爱你,你永远是我的好老公
我说:都是我的好老婆....
老婆5说:老公我爱你,你永远是我的好老公
我说:都是我的好老婆....
老婆6说:老公我爱你,你永远是我的好老公
我说:都是我的好老婆....
结果分析:
从上面代码我们发现,我们所构造的每一个对象都是同一个实例。
(嘎嘎,都是我的老婆呀。)
4.为什么需要Singleton
刚接触单例的人肯定都会有和我相同的疑问:为什么我们需要单例。有人肯定会说:单例可以减少内存空间的开辟。这个说法没有错,但是这不是单例存在的实质。单例存在的实质主要是:
数据共享——可以在不建立直接关联的条件下,让多个不相关的两个线程或者进程之间实现通信。比如,数据库连接池的设计一般采用单例模式,数据库连接是一种数据库资源;控制资源的使用,通过线程同步来控制资源的并发访问;控制实例产生的数量,达到节约资源的目的。
5. Singleton使用场景
简而言之,就是任何只需要一个实例的地方.例如,窗口管理器,假脱机打印设备,数据库连接池。具体应用中,配置信息类,管理类,控制类,门面类,代理类通常被设计为单例类.
(1)读取配置文件的类:比如你的工程需要读取配置文件,一般情况下你会写个配置文件的类,而这个类在整个工程里只需要new一次,所有调用者都是用同一个实例,那么这个类就可以采用单例模式。
(2)管理器的类:一些管理器的类都是单例的,所有跟管理有关的操做都要调用管理器来进行,管理器不能出现多个,所以要单例,避免管理混乱。
(3)日志操作类:你如果多个实例打开同一个文件写日志,那肯定是不行的(当然,如果你非要多个实例之间做同步,打开文件,写,关,然后下一个实例,这种,那性能就不行了)。
(4)配置信息类:负责配置文件的解析,通常被设计为单例类。
(5)管理类:如连接池管理类,通常被设计为单例类。
(6)控制类:如struts的ActionServlet类,也是单例类。
(7)门面类:说到门面类,就不能不提门面(Facade)模式。客户端与多个子系统的通信必须通过一个统一的门面(Facade)对象进行,这就是门面模式。这个统一的门面(Facade)对象就是门面类。在门面模式中,通常只需要一个门面类,并且此门面类只有一个实例,换言之它是一个单例类。但这不是绝对的。
(8)代理类:在Jive中,使用代理模式实现权限访问的入口,就采用了单例模式。