`
aladdin_leon
  • 浏览: 118478 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
社区版块
存档分类
最新评论

单体模式(Singleton)备忘录

阅读更多

1.单体模式的宗旨
     单体模式的宗旨在于确保某个类只有唯一的一个实例,并且为该类提供一个全局的访问点。
     当我们开发项目时,经常会发现一些类需要只有一个实例,比如:Window Manager,Print Spooler,对数据库引擎的唯一访问点等等。单体模式被GoF归于创建型的模式,但我认为它应归位责任型的模式,因为单体模式的价值在于将一个类的职责集中在唯一的一个单体对象之中。

2.单体模式的实现
     单体模式的实现有很多种,每种都有自身的优点和缺点,但是宗旨都是确保单体的唯一。由于static关键字的“天生资质”,注定了它与单体模式的“姻缘”。下面罗列出几种实现方法,假设的场景都是:将PrintSpooler类设计为单体,现在就让我们一起来比较一下吧!
     a.通过Exception机制
     首先为了程序更加清晰,我们自己定义一个异常类SingletonException:

  1. public class SingletonException extends RuntimeException {   
  2.       public SingletonException() {   
  3.             super();   
  4.       }   
  5.       public SingletonException(String s) {   
  6.             super(s);   
  7.       }   
  8. }     

      接下来就是单体模式关键的部分:

  1. public class PrintSpooler {   
  2.       static boolean instance_flag=false//true if 1 instance   
  3.       public PrintSpooler() throws SingletonException {   
  4.             if (instance_flag)   
  5.                   throw new SingletonException("Only one spooler allowed");   
  6.            else  
  7.                   instance_flag = true//set flag for 1 instance   
  8.                   System.out.println("spooler opened");   
  9.       }   
  10.       public void finalize() {   
  11.             instance_flag = false//clear if destroyed   
  12.       }   
  13. }  

       现在为止,PrintSpooler单体设计已经完成,让我们看看如何使用它:

  1. public class singleSpooler {   
  2.       static public void main(String argv[]) {   
  3.             PrintSpooler pr1, pr2;   
  4.             System.out.println("Opening one spooler");   
  5.             try {   
  6.                   pr1 = new PrintSpooler();   
  7.             } catch (SingletonException e) {   
  8.                   System.out.println(e.getMessage());   
  9.             }   
  10.             System.out.println("Opening two spoolers");   
  11.             try {   
  12.                   pr2 = new PrintSpooler();   
  13.             } catch (SingletonException e) {   
  14.                   System.out.println(e.getMessage());   
  15.            }   
  16.       }   
  17.  }   

       运行结果如下:
           Opening one spooler
           printer opened
           Opening two spoolers
           Only one spooler allowed
     通过结果我们可以很清楚的发现我们程序完成了设计的意图确保了实例的唯一,但是这种方法的缺点就是我们必须把调用代码包在try-catch块之中,使简单的调用变得太复杂了,对于具有“懒惰”美德的程序员来说,这样有一些太笨了......

      b.通过final和static
      看看下面的解决方案:

  1. final class PrintSpooler {   
  2.       static public void print(String s) {   
  3.             System.out.println(s);   
  4.        }   
  5. }   

      如何使用:

  1. public class staticPrint {   
  2.       public static void main(String argv[]) {   
  3.             Printer.print("here it is");   
  4.       }   
  5. }    


      将PrintSpooler设计为final约束的,这样它就不能被其他类所扩张(继承),通过static的特性确保内存中实例的唯一,直接通过类名调用方法。不过这看上去更像一个工具类了啊,不错,Java的Math库正是采取这种设计的,当然这种设计的缺点就是我们对PrintSpooler的约束过于强大了。
 
     c.GoF的解决方案
     下面让我们看看最流行的解决方案吧,当然也是我们在项目中用到的最广泛的GoF的那本“设计模式圣经”里面所描述的:

  1. public class PrintSpooler {     
  2.       private PrintSpooler(){}      
  3.    private static PrintSpooler instance = new PrintSpooler();      
  4.       public static PrintSpooler getInstance() {       
  5.             return instance;      
  6.       }   
  7. }    

     神奇吗?把构造函数设为private的,这样的话外部就不能实例化PrintSpooler类,只有自己本身能够实例化自己,然后通过静态方法getInstance()返回这个实例从而提供唯一的访问点。如果你试着运行这行代码:
             PrintSpooler p = new PrintSpooler();
     ^_^,编译器是不会放过你的!那么我们如何使用PrintSpooler呢?很简单,我们敲下这行代码就可以了:
             PrintSpooler p = PrintSpooler.getInstance();
    这个解决方案还有另外一种变形,就是用到Lazy-initialize:

  1. public class PrintSpooler {     
  2.       private PrintSpooler(){}      
  3.    private static PrintSpooler instance = null;      
  4.       public static synchronized PrintSpooler getInstance() {       
  5.              if(instance == null)   
  6.              instance = new PrintSpooler();    
  7.              return instance;      
  8.       }   
  9. }    

     这里有两个问题需要解决:为什么需要 Lazy-initialize?它是什么 ?
                                                     那里冒出的 synchronized ?
     首先,因为有时候单体类在实例化时所需的数据只有在运行时通过计算才能获得,所以我们必须延迟实例化,所以也就有了先前的惰性初始化(Lazy-initialize)--第一次调用时进行初始化。
     其次,考虑的线程安全的因素,如果一个线程发现instance==null而去实例化PrintSpooler,且此时PrintSpooler还未实例化完毕。与此同时另一线程也检查instance,结果为instance==null,所以也去实例化PrintSpooler了,现在PrintSpooler有了两个实例,不再是单体了。为了防止上面的情况发生,可以用synchronized提供的锁机制,所以就冒出了synchronized!

3.需要注意的问题
     有时在某些情况下,使用Singleton并不能达到Singleton的目的,如有多个Singleton对象同时被不同的类装入器装载;在EJB这样的分布式系统中使用也要注意这种情况,因为EJB是跨服务器和JVM的。所以在EJB中,单体模式就失效了!

4.再罗嗦一些......
     在工厂模式中的类装载器(Class Loader)就是一个单体,J2EE设计模式中的ServiceLocator也是一个单体...我们仔细观察会发现我们的项目中在不知不觉用到好多的单体,其实单体模式的实现并没有难点,真正的难点在于在系统中如何识别单体和不滥用单体,这种敏感性只有不断的实践中才能锻炼出来,所以用好Singleton是非常不容易的事情......

分享到:
评论

相关推荐

    Java常用设计模式(SingleTon、FactoryMethod、AbstractFactory)

    这里我们将深入探讨三种常见的Java设计模式:单例(Singleton)、工厂方法(Factory Method)和抽象工厂(Abstract Factory)。 **单例模式(Singleton)** 单例模式确保一个类只有一个实例,并提供一个全局访问点...

    C# 备忘录(源码)——烽火系列

    8. **设计模式**:虽然这是一个简单的项目,但可能也涉及到一些基础的设计模式,比如单例模式(Singleton)用于控制备忘录对象的唯一性,或者工厂模式(Factory)来创建不同类型的备忘项。 通过这个项目,初学者...

    Java 单例模式Singleton

    简单的单例模式举例Singleton 分为恶汉式 懒汉式

    .NET c# 单体模式(Singleton)

    ### .NET C# 单体模式(Singleton)详解 #### 一、单体模式概述 单体模式(Singleton)是一种常用的软件设计模式,它保证一个类只有一个实例,并提供一个全局访问点。这种模式通常用于控制资源访问,比如数据库...

    单例模式Singleton(java源码)

    Singleton模式包含的角色只有一个,就是Singleton。Singleton拥有一个私有构造函数,确保用户无法通过new直接实例化它。除此之外,该模式中包含一个静态私有成员变量instance与静态公有方法Instance()。Instance()...

    Qt qml Singleton 单例模式

    在Qml中,我们可以通过Qt的Singleton组件来实现这一模式。 首先,让我们理解单例模式的基本概念。在软件工程中,单例模式保证一个类只有一个实例,并提供一个全局访问点。这个设计模式在许多场景下都很实用,比如...

    设计模式 创建型模式 Singleton模式(单键)

    Singleton模式: 确保一个类只有唯一的一个实例。 Singleton主要用于对象的创建,这意味着,如果某个类采用了Singleton模式,则在这个类被创建后,它将有且仅有一个实例可供访问。很多时候我们都会需要Singleton...

    javascript 设计模式之单体模式 面向对象学习基础

    JavaScript中的单体模式是一种设计模式,它用于确保一个类只有一个实例,并提供一个全局访问点来获取这个唯一实例。这种模式在JavaScript中尤其重要,因为JavaScript是全局作用域的语言,容易导致变量冲突。单体模式...

    C++完美实现Singleton模式

    ### C++中实现Singleton模式的关键知识点 #### 一、Singleton模式简介 Singleton模式是一种常用的软件设计模式,旨在确保一个类只有一个实例,并提供一个全局访问点。这种模式在系统中经常被用于控制对共享资源...

    单例模式 Singleton Pattern

    ### 单例模式 Singleton Pattern #### 概述 单例模式是一种常见的设计模式,属于创建型模式之一。这种模式的核心在于确保某个类只有一个实例存在,并且提供一个全局访问点来获取该实例。单例模式在Java开发中尤其...

    C++ 实现的singleton 模式

    **C++实现的Singleton模式详解** Singleton模式是一种常用的软件设计模式,它保证一个类只有一个实例,并提供一个全局访问点。这种模式在很多场景下都非常有用,例如管理共享资源,如数据库连接池,或者确保某个...

    (创建型模式)Singleton模式

    Singleton模式是设计模式中的一种创建型模式,它在软件工程中扮演着重要的角色。这个模式的主要目的是确保一个类只有一个实例,并提供一个全局访问点来获取这个唯一的实例。Singleton模式的应用场景通常涉及到系统...

     单例设计模式Singleton1

    单例设计模式Singleton1是Java设计模式中的一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点。这个模式的核心知识点可以总结为三点: 1. ...

    设计模式-Singleton与Factory

    设计模式-Singleton与Factory

    单例模式Singleton

    单例模式(Singleton Pattern)是一种常用的软件设计模式,它的核心思想是确保一个类在整个应用程序中只有一个实例存在,并提供一个全局访问点来获取这个实例。这种模式在很多场景下非常有用,比如管理系统资源、...

    最简单的设计模式学习Singleton模式

    ### 最简单的设计模式学习:Singleton模式 #### 一、Singleton模式简介 Singleton(单例)模式是一种常用的软件设计模式,其主要目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式在许多场合下非常...

    单例模式(singleton)

    单例模式是软件设计模式中的一种,它的核心思想是确保一个类在整个系统中只有一个实例,并提供一个全局访问点。在Java或类似编程语言中,单例模式常常被用来管理资源,比如数据库连接、线程池或者配置信息,因为这些...

    C#设计模式之Singleton模式

    《C#设计模式之Singleton模式详解》 Singleton模式是软件设计模式中的一种基础模式,它在众多设计模式中占有重要地位,尤其在C#编程中经常被应用。Singleton模式的主要目的是确保一个类只有一个实例,并提供一个...

Global site tag (gtag.js) - Google Analytics