在Java中应用设计模式--Singleton

转载 2006年06月23日 14:34:00
在Java中应用设计模式--Singleton

作者:刘湛    来自:IBM

  本文介绍了设计模式中 Singleton 的基本概念,对其功能和用途进行了简单的分析,列出了通常实现 Singleton 的几种方法,并给出了详细的Java 代码.

  基本概念

  Singleton 是一种创建性模型,它用来确保只产生一个实例,并提供一个访问它的全局访问点.对一些类来说,保证只有一个实例是很重要的,比如有的时候,数据库连接或 Socket 连接要受到一定的限制,必须保持同一时间只能有一个连接的存在.再举个例子,集合中的 set 中不能包含重复的元素,添加到set里的对象必须是唯一的,如果重复的值添加到 set,它只接受一个实例.JDK中正式运用了Singleton模式来实现 set 的这一特性,大家可以查看java.util.Collections里的内部静态类SingletonSet的原代码.其实Singleton是最简单但也是应用最广泛的模式之一,在 JDK 中随处可见.

  简单分析

  为了实现 Singleton 模式,我们需要的是一个静态的变量,能够在不创建对象的情况下记忆是否已经产生过实例了.静态变量或静态方法都可以在不产生具体实例的情况下直接调用,这样的变量或方法不会因为类的实例化而有所改变.在图1的结构中可以看到,uniqueInstance 就是这个独立的静态变量,它可以记忆对象是否已经实例化了,在静态方法 Instance 中对这个变量进行判断,若没有实例化过就产生一个新的对象,如果已经实例化了则不再产生新的对象,仍然返回以前产生的实例.


图1: Singleton 模式结构

  具体实施

  实现 Singleton 模式的办法通常有三种.

  一. 用静态方法实现 Singleton

  这种方法是使用静态方法来监视实例的创建.为了防止创建一个以上的实例,我们最好把构造器声明为 private.

  这样可以防止客户程序员通过除由我们提供的方法之外的任意方式来创建一个实例,如果不把构造器声明为private,编译器就会自作聪明的自动同步一个默认的friendly构造器.这种实现方法是最常见的,也就是图1中结构的标准实现.

        public class Singleton {
            private static Singleton s;
            private Singleton(){};
        /**
             * Class method to access the singleton instance of the class.
         */
        public static Singleton getInstance() {
         if (s == null)
            s = new Singleton();
          return s;
        }
}

// 测试类
class singletonTest {
  public static void main(String[] args) {
    Singleton s1 = Singleton.getInstance();
    Singleton s2 = Singleton.getInstance();
    if (s1==s2)
      System.out.println("s1 is the same instance with s2");
    else
      System.out.println("s1 is not the same instance with s2");
  }
}

  singletonTest运行结果是:
  s1 is the same instance with s2
  这证明我们只创建了一个实例.

  二. 以静态变量为标志实现 Singleton

  在类中嵌入一个静态变量做为标志,每次都在进入构造器的时候进行检查.

  问题在于构造器没有返回类型,如果确定创建一个实例成功与否.一个方法是调用一个函数来检查创建是否成功,然后简单的返回一个来自静态变量的值,但是这样做是不优雅的,而且容易发生错误.比较好的做法是创建一个当创建了一个以上的实例时可以抛出异常的类,这个类仅仅是调用父类方法,好处是用了自己命名的异常类型,错误信息更加清晰:

class SingletonException extends RuntimeException {
  public SingletonException(String s) {
    super(s);
  }
}

class Singleton {
  static boolean instance_flag = false; // true if 1 instance
  public Singleton() {
    if (instance_flag)
      throw new SingletonException("Only one instance allowed");
    else
      instance_flag = true; // set flag for 1 instance
  }
}

// 测试类

public class singletonTest {
  static public void main(String argv[]) {
    Singleton s1, s2;
    // create one incetance--this should always work
    System.out.println("Creating one instance");
    try {
      s1 = new Singleton();
    } catch (SingletonException e) {
      System.out.println(e.getMessage());
    }
    // try to create another spooler --should fail
    System.out.println("Creating two instance");
    try {
      s2 = new Singleton();
    } catch (SingletonException e) {
      System.out.println(e.getMessage());
    }
  }
}

  singletonTest运行结果是:
  Creating one instance
  Creating two instance
  Only one instance allowed
  可以看出,第一个实例顺利创建,第二个实例创建实抛出了我们自定义的异常.

  三. 用注册器机制来创建 Singleton

  首先用集合中的Hashtable 和Enumeration来实现addItem(Object key, Object value),getItem(Object key), ,removeItem(Object key)等方法实现一个管理器,将key和value一一关联起来,客户程序员创建实例前首先用addItem方法进行注册,再用getItem方法获取实例.Hashtable中的key是唯一的,从而保证创建的实例是唯一的,具体实现限于篇幅不再细说,在Prototype模型的应用一文中我将会给出一个实现注册器的代码.用注册器机制来创建 Singleton模式的好处是易于管理,可以同时控制多个不同类型的Singleton 实例.

  小结

  1. Singleton模式可以方便的进行扩充,产生指定数目的实例.

  2. 在The Design Patterns Java Companion 一书中曾提到过用静态类的方式来实现 Singleton模式,并指出java.lang.Math就是一个例子,这里我并不表示赞同,因为Math并不是一个真正的对象,我们只是直接调用Math类所包装的静态方法而已,根本就没有创建实例的过程,又从何说起只产生一个实例呢?这个问题我曾到Javaranch的论坛上发过帖子,所有回帖的人也都是对这一观点持否定态度.

  3. 在多线程的程序中,singleton可能会变的不可靠,可能会出现多个实例,解决的办法很简单,加个同步修饰符: public static synchronized Singleton getInstance(). 这样就保证了线程的安全性.

  4. 最后要说的是大家可能会看见一些其他实现Singleton模式的方法,因为模式在具体的应用时是灵活的,不是一成不变的,并没有一个固定的做法,但大都是上面几种方法的变形.

java实现单例singleton的几种模式

Singleton的4种实现方式1.静态工厂实现法静态工场估计是最常用的单例实现方式,例子如下(详细见注解)// 静态工厂实现法 public class CommonSingleton { /...
  • u012233832
  • u012233832
  • 2016年08月08日 23:37
  • 357

C++中多线程与Singleton的那些事儿

前言 前段时间在网上看到了个的面试题,大概意思是如何在不使用锁和C++11的情况下,用C++实现线程安全的Singleton。 看到这个题目后,第一个想法就是用Scott Meyer在《Effec...
  • zmlcool
  • zmlcool
  • 2016年06月11日 17:56
  • 775

Java 写一个单例模式(Singleton)出来

第一种:饱汉模式 public class SingleTon {  private SingleTon(){ } //实例化放在静态代码块里可提高程序的执行效率,但也可能更占用空间 ...
  • zpf336
  • zpf336
  • 2014年09月25日 21:41
  • 7830

“一盘沙拉”带你入门Dagger2(四)之 @Singleton

@Singleton可以方便地实现单例(全局单例)我们在Salad类里面引入两个Orange的实例,查看他们的内存地址public class Salad { @Inject//桔子1 O...
  • Android_Study_OK
  • Android_Study_OK
  • 2016年09月02日 16:42
  • 2771

基于软引用的单例缓存

原创文章,转载请注明               把软引用和单例结合,实现一个简单的缓存。       1、软引用               软引用对于缓存的实现是非常适用的。软引用在内存存在压力...
  • guduyishuai
  • guduyishuai
  • 2017年03月03日 15:58
  • 282

java当中的单例模式

java当中单例模式用得非常的多,特别是我在安卓开发当中
  • realrealrealrealreal
  • realrealrealrealreal
  • 2014年11月05日 00:18
  • 646

设计模式之——单例模式(Singleton)的常见应用场景

单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此...
  • likika2012
  • likika2012
  • 2013年09月09日 16:43
  • 48659

每天一题(48) - C++实现Singleton模式

饿汉模式 代码(1) //.h文件 class Singleton { public: static Singleton& GetInstance(); private: Singleton(){...
  • insistGoGo
  • insistGoGo
  • 2013年07月22日 19:37
  • 3385

Python和Singleton (单件)模式

我知道的一种在 python 中 Singleton mode 的实现如下: class Foo: pass def instance():     global inst ...
  • new_abc
  • new_abc
  • 2015年08月23日 12:09
  • 1258

C++ Singleton模式之线程安全

转自: http://blog.csdn.net/insistgogo/article/details/9412863 定义: 保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程...
  • nodeathphoenix
  • nodeathphoenix
  • 2016年06月13日 15:09
  • 742
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在Java中应用设计模式--Singleton
举报原因:
原因补充:

(最多只允许输入30个字)