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

设计

本文介绍了设计模式中 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模式的方法,因为模式在具体的应用时是灵活的,不是一成不变的,并没有一个固定的做法,但大都是上面几种方法的变形. 

时间: 2024-08-30 02:32:28

在Java中应用设计模式--Singleton的相关文章

请问这是java中的设计模式吗?

问题描述 请问这是java中的设计模式吗? 请问下面的代码属于什么设计?为什么把set方法改成那样子 public class A{ private Integer num; private String min; public Integer gerNum(){ return num; } public A num(Integer num){ this.num = num; return this; } public String getMin(){ return min; } public

在Java中应用设计模式--Factory Method

设计 在设计模式中,Factory Method也是比较简单的一个,但应用非常广泛,EJB,RMI,COM,CORBA,Swing中都可以看到此模式的影子,它是最重要的模式之一.在很多地方我们都会看到xxxFactory这样命名的类,那么,什么是Factory Method,为什么要用这个模式,如何用Java语言来实现该模式,这就是本文想要带给大家的内容. 基本概念 Factory Method是一种创建性模式,它定义了一个创建对象的接口,但是却让子类来决定具体实例化哪一个类.当一个类无法预料要

在Java中应用设计模式之Singleton

基本概念 ingleton 是一种创建性模型,它用来确保只产生一个实例,并提供一个访问它的全局访问点.对一些类来说,保证只有一个实例是很重要的,比如有的时候,数据库连接或 Socket 连接要受到一定的限制,必须保持同一时间只能有一个连接的存在. 再举个例子,集合中的 set 中不能包含重复的元素,添加到set里的对象必须是唯一的,如果重复的值添加到 set,它只接受一个实例.JDK中正式运用了Singleton模式来实现 set 的这一特性,大家可以查看java.util.Collection

Java中使用设计模式来优化命令行交互程序的开发

人机交互的方式最初起始于命令行交互,虽然图形界面的交互方式应用越来越广泛,可是命令行交互仍然有着它不可替代的地位.命令行交互程序是以命令行方式进行的http://www.aliyun.com/zixun/aggregation/11432.html">人机交互,即用户按着程序的提示,一步步进行输入,而程序负责解释并最终执行指令. 本文以一个简单的部署 war 包的实例,说明在命令行交互程序设计中遇到的问题,以及如何使用设计模式来解决这些问题. 实例简介 在实例中,命令行交互程序给出了一组问

从Java类库看设计模式(5)

有了前面诸多设计模式的基础,这儿可以提出一个比较特殊的模式MVC.MVC并不属于GOF 的23个设计模式之列,但是它在GOF的书中作为一个重要的例子被提出来,并给予了很高的评 价.一般的来讲,我们认为GOF的23个模式是一些中级的模式,在它下面还可以抽象出一些更 为一般的低层的模式,在其上也可以通过组合来得到一些高级的模式.MVC就可以看作是一些 模式进行组合之后的结果(实际上,MVC的出现要早于设计模式的提出,这而只是对它在设计 模式的基础上进行在分析).如果没有前面的基础,理解MVC或许会有

设计模式Observer在java中的应用

Java深入到一定程度,就不可避免的碰到设计模式(design pattern)这一概念,了解设 计模式,将使自己对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统 中应用广泛,遵循一定的编程模式,才能使自己的代码便于理解,易于交流,Observer(观察 者)模式是比较常用的一个模式,尤其在界面设计中应用广泛,而本站所关注的是Java在电 子商务系统中应用,因此想从电子商务实例中分析Observer的应用. 虽然网上商店形式多样,每个站点有自己的特色,但也有其一般的共性,

Java结构型设计模式中的适配器模式与桥接模式解析_java

适配器模式 定义 适配器模式(英语:adapter pattern)有时候也称包装样式或者包装.将一个类的接口转接成用户所期待的.一个适配使得因接口不兼容而不能在一起工作的类工作在一起. 有两类适配器模式: 1. 对象适配器模式 - 对象适配器通过关联满足用户期待接口,还降低了代码间的不良耦合.在工作中推荐使用"对象适配". 2. 类适配器模式 - 这种适配器模式下,适配器继承自已实现的类(一般多重继承),java中没有多重继承,所以这里不做介绍. 实现 1. Target - 定义C

软件行为模型中的设计模式

Discovering design patterns in software behavior models Sandeep Mitra and T. M. Rao Department of Computing Sciences The College at Brockport, State University of New York Brockport, NY 14420 585 395-2234 smitra@brockport.edu 探索软件行为模型中的设计模式 Sandeep M

聊聊 Java 中 HashMap 初始化的另一种方式

如果你接触过不同的语言,从语法和代码层面来说,Java 是一种不折不扣的"臃肿.啰嗦"的语言,从另一方面来说这种臃肿和啰嗦也体现了它严谨的一面,作为适合构建大型.复杂项目的理由之一. 1.HashMap 初始化的文艺写法 HashMap 是一种常用的数据结构,一般用来做数据字典或者 Hash 查找的容器.普通青年一般会这么初始化: HashMap<String, String> map = new HashMap<String, String>(); map.p