单例模式的学习

目前在读阎宏的这本《Java与模式》,看到了单例模式,总结一下。

(注明:本文中的代码是从阎宏老师书中拷贝过来的)

在书中提到了饿汉式、懒汉式以及登记式单例类。

 

饿汉式的结构如下

public class EagerSingleton

{

        private static final EagerSingleton m_instance = new EagerSingleton();

        /**

         * 私有的默认构造方法

         */

        private EagerSingleton(){}

        /**

         * 静态工厂方法

         */

        public static EagerSingleton getInstance()

        {

                   return m_instance;

         }

}

 

从代码结构上看,当EagerSingleton类加载时,就会实例化静态变量m_instance,与此同时私有的构造方法也被调用到。这样EagerSingleton的唯一实例就被创建了。(题外话,为啥叫饿汉式呢?当一个人饿的时候,会不考虑其他的,首先先吃点儿东西再说,那么这里就是先调用一次构造方法再说咯,呵呵……阎宏老师的书中有很多这样的类比)

 

懒汉式的结构如下:

public class LazySingleton

{

         private static LazySingleton m_instance = null;

         /**

          * 私有的默认构造方法,保证外界无法直接实例化

          */

         private LazySingleton() {}

         /**

          *  静态工厂方法,返还此类的唯一实例

          */

         synchronized public static LazySingleton getInstance()

         {

                  if ( m_instance == null )

                  {

                          m_instance = new LazySingleton();

                  }

                  return m_instance;

          }

}

从代码结构上看,当LazySingleton类加载时,首先会对m_instance静态变量实例化一个null对象,当真正需要使用LazySingleton类时调用getInstance()方法返回一个LazySingleton类实例(题外话,只有需要时才会去使用,比较懒的做法,不会提前准备好,因此叫懒汉式)。注意到,在获得实例的方法前面加了关键字synchronized,这个关键字一般是为了保证线程安全时才会被使用,这里被阎宏老师说成了“双重检查成例”。如果不加可不可以呢?可以,不过要在单线程环境下运行。如果在多线程环境下运行会出现产生多实例争夺资源的情况,我们不能保证计算机会不会在同一时间里多线程调用getInstance方法。因此必须注意在实例化时多线程的同时首次引用此类时的访问权限。

 

登记式单例类(也叫注册式单例类)的结构如下

 

package com.javapatterns.singleton.demos;

 

import java.util.HashMap;

 

public class RegSingleton

{

         private static HashMap m_registry = new HashMap();

         static

         {

                 RegSingleton x = new RegSingleton();

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

          }

          /**

           *  保护的默认构造方法

           */

          protected RegSingleton() {}

          /**

           *  静态工厂方法,返还此类的唯一实例

           */

         public static RegSingleton getInsatnce(String name)

         {

                if (name == null)

                {

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

                }

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

                {

                       try {

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

                       }

                       catch(Exception e)

                       {

                             System.out.println("Error happend.");

                        }

                 }

                 return (RegSingleton) m_registry.get(name);

          }

          /**

           * 一个示意性的商业方法

           */

          public String about()

          {

                  return "Hello, I am RegSingleton";

           }

}

登记式单例方法解决了前面两个列子无法解决的子类继承问题。在本例中,阎宏老师将实例化的方式从懒汉式改为了饿汉式,只是它的子类实例化方式只能是懒汉式的,且无法改变。

下面是子类的代码结构

package com.javapatterns.singleton.demos;

import java.util.HahMap;

public class RegSingletonChild extends RegSingleton

{

        public RegSingletonChild() {}

        /**

         *  静态方法工厂

         */

        public static RegSingletonChild getInstance()

        {

                return (RegSingletonChild) RegSingleton.getInstance("com.javapatterns.singleton.demos.RegSingletonChild");

        }

        /**

         * 一个示意性的商业方法

         */

        public String about()

        {

                return "Hello, I am RegSingletonChild";

        }

}

由于子类必须允许弗雷以构造方法调用产生实例,因此,它的构造方法必须是公开的。这样一来,就等于允许了以这样的方式产生实例而不在父类的登记中。这是登记式单例类的一个缺点。

 

各尽所需,各取所求,实现的方式有很多种,根据自己的系统需要选用不同的设计模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值