现在的位置: 首页 > 综合 > 正文

Java 单例模式

2013年10月05日 ⁄ 综合 ⁄ 共 10897字 ⁄ 字号 评论关闭

转载自:http://en.wikipedia.org/wiki/Singleton_pattern#The_Enum_way

Singleton pattern

From Wikipedia, the free encyclopedia

In software engineering, the singleton
pattern
 is a design pattern that restricts the instantiation of
a class to one object. This is useful when exactly one object is needed to coordinate actions across
the system. The concept is sometimes generalized to systems that operate more efficiently when only one object exists, or that restrict the instantiation to a certain number of objects. The term comes from the mathematical
concept of a singleton
.

There is criticism of the use of the singleton pattern, as some consider it an anti-pattern,
judging that it is overused, introduces unnecessary restrictions in situations where a sole instance of a class is not actually required, and introduces global
state
 into an application.[1][2][3][4][5][6]

In C++ it also serves to isolate from the unpredictability of the order of dynamic
initialization, returning control to the programmer.

Contents

  [hide

[edit]Common
uses

  • The Abstract FactoryBuilder,
    and Prototype patterns can use Singletons in their implementation.
  • Facade Objects are often Singletons because only one Facade object is required.
  • State objects are often Singletons.
  • Singletons are often preferred to global variables because:
    • They do not pollute the global name space (or, in languages with namespaces, their containing namespace) with unnecessary variables.[7]
    • They permit lazy allocation and initialization, whereas global variables in many languages will
      always consume resources.

[edit]UML

Singleton.png

[edit]Implementation

Implementation of a singleton pattern must satisfy the single instance and global access principles. It requires a mechanism to access the singleton class member without creating
a class object and a mechanism to persist the value of class members among class objects. The singleton pattern is implemented by creating a class with
a method that creates a new instance of the class if one does not exist. If an instance already exists, it simply returns a reference to that object. To make sure that the object cannot be instantiated any other way, the constructor is
made private. Note the distinction between a simple static instance of a class and a singleton:
although a singleton can be implemented as a static instance, it can also be lazily constructed, requiring no memory or resources until needed. Another notable difference is that static member classes cannot implement an interface,
unless that interface is simply a marker. So if the class has to realize a contract expressed by an interface, it really has to be a singleton.

The singleton pattern must be carefully constructed in multi-threaded applications.
If two threads are to execute the creation method at the same time when a singleton does not yet exist, they both must check for an instance of the singleton and then only one should create the new one. If the programming language has concurrent processing
capabilities the method should be constructed to execute as a mutually exclusive operation.

The classic solution to this problem is to use mutual exclusion on
the class that indicates that the object is being instantiated. Unfortunately, in Java hacking singleton can not be solved, unless one uses fully static class. See the sections below.

[edit]Example

The Java programming language solutions
provided here are all thread-safe but differ in supported language versions and lazy-loading.
Since Java 5.0, the easiest way to create a Singleton is the enum type approach, given at the end of this section.

[edit]Lazy
initialization

This method uses double-checked
locking
, which should not be used prior to J2SE 5.0, as it is vulnerable to subtle bugs.
The problem is that an out-of-order write may allow the instance reference to be returned before the Singleton constructor
is executed.[8]

public class SingletonDemo {
        private static volatile SingletonDemo instance = null;
 
        private SingletonDemo() {       }
 
        public static SingletonDemo getInstance() {
                if (instance == null) {
                        synchronized (SingletonDemo .class){
                                if (instance == null) {
                                        instance = new SingletonDemo ();
                                }
                      }
                }
                return instance;
        }
}

[edit]Eager
initialization

If the program will always need an instance, or if the cost of creating the instance is not too large in terms of time/resources, the programmer can switch to eager initialization, which always
creates an instance:

public class Singleton {
    private static final Singleton instance = new Singleton();
 
    private Singleton() {}
 
    public static Singleton getInstance() {
        return instance;
    }
}

This method has a number of advantages:

  • The instance is not constructed until the class is used.
  • There is no need to synchronize the getInstance() method,
    meaning all threads will see the same instance and no (expensive) locking is required.
  • The final keyword means that the instance cannot be redefined, ensuring that one (and only one) instance ever exists.

This method also has some drawbacks:

  • If the program uses the class, but perhaps not the singleton instance itself, then you may want to switch to lazy initialization.

[edit]Static
block initialization

Some authors[9] refer
to a similar solution allowing some pre-processing (e.g. for error-checking). In this sense, the traditional approach could be seen as a particular case of this one, as the class loader would do exactly the same processing.

public class Singleton {
  private static final Singleton instance;
 
  static {
    try {
      instance = new Singleton();
    } catch (IOException e) {
      throw new RuntimeException("Darn, an error occurred!", e);
    }
  }
 
  public static Singleton getInstance() {
    return instance;
  }
 
  private Singleton() {
    // ...
  }
}

[edit]The
solution of Bill Pugh

University of Maryland Computer
Science researcher Bill Pugh has written about the code issues underlying the Singleton pattern when implemented in Java.[10] Pugh's
efforts on the "Double-checked locking" idiom led to changes in the Java memory model in Java 5 and to what is
generally regarded as the standard method to implement Singletons in Java. The technique known as the initialization
on demand holder idiom
, is as lazy as possible, and works in all known versions of Java. It takes advantage of language guarantees about class initialization, and will therefore work correctly in all Java-compliant compilers and virtual machines.

The nested class is referenced no earlier (and therefore loaded no earlier by the class loader) than the moment that getInstance() is called. Thus, this solution isthread-safe without
requiring special language constructs (i.e. volatile or synchronized).

public class Singleton {
        // Private constructor prevents instantiation from other classes
        private Singleton() { }
 
        /**
        * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
        * or the first access to SingletonHolder.INSTANCE, not before.
        */
        private static class SingletonHolder { 
                public static final Singleton INSTANCE = new Singleton();
        }
 
        public static Singleton getInstance() {
                return SingletonHolder.INSTANCE;
        }
}

Alternatively, the inner class SingletonHolder can be also substituted by implementing a Property which provides also access to the static final/read-only class members. Just like the lazy
object in C#, whenever the Singleton.INSTANCE property is called, this singleton is instantiated for the very first time.

Unfortunately, this solution does not prevent reflection based way of creating a class. For example, below is the code that goes past the single instance :-

import java.lang.reflect.*;
 
public class Main {
 
        public static Singleton createAnotherOne()
        {
                Singleton singleton = null ;
                try{
                 Constructor[]  cs = Singleton.class.getDeclaredConstructors();
                        for ( Constructor c : cs ){
                                //This is where people can destroy the pattern.
                                c.setAccessible( true );
                                singleton = (Singleton)c.newInstance();
                                break;
                        }
                }catch (Exception e){
                                e.printStackTrace();
                }
                return singleton;
        }
 
    public static void main(String[] args) {
        System.out.println(Singleton.getInstance().hashCode() );
            System.out.println( createAnotherOne().hashCode() );
 
    }
}

[edit]The
Enum way

In the second edition of his book Effective JavaJoshua
Bloch
 claims that "a single-element enum type is the best way to implement a singleton"[11] for
any Java that supports enums. The use of an enum is very easy to implement and has no drawbacks regarding serializable objects, which have to be circumvented in the other ways.

public enum Singleton {
        INSTANCE;
        public void execute (String arg) {
                //... perform operation here ...
        }
}

The public method can be written to take any desired types of arguments; a single String argument is used here as an example.

This approach implements the singleton by taking advantage of Java's guarantee that any enum value is instantiated only once in a Java program. Since Java enum values are globally accessible,
so is the singleton. The drawback is that the enum type is somewhat inflexible; for example, it does not allow lazy initialization.

[edit]Prototype-based
singleton

In a prototype-based programming language,
where objects but not classes are used, a "singleton" simply refers to an object without copies or that is not used as the prototype for any other object. Example in Io:

Foo := Object clone
Foo clone := Foo

[edit]Example
of use with the factory method pattern

The singleton pattern is often used in conjunction with the factory
method pattern
 to create a system-wide resource whose specific type is not known to the code that uses it. An example of using these two patterns together is the Java Abstract
Window Toolkit
 (AWT).

java.awt.Toolkit is
an abstract class that binds the
various AWT components to particular native toolkit implementations. The Toolkit class has aToolkit.getDefaultToolkit() factory
method that returns the platform-specific subclass of Toolkit.
The Toolkit object is a singleton because the AWT needs only a single object to perform the binding and the object is relatively expensive to create. The toolkit methods
must be implemented in an object and not as static methods of a class because the specific implementation is
not known by the platform-independent components. The name of the specific Toolkit subclass used is specified by the "awt.toolkit"environment
property
 accessed through System.getProperties().

The binding performed by the toolkit allows, for example, the backing implementation of a java.awt.Window to
bind to the platform-specific java.awt.peer.WindowPeerimplementation. Neither the Window class
nor the application using the window needs to be aware of which platform-specific subclass of the peer is used.

[edit]Drawbacks

This pattern makes unit testing far more difficult,[6] as
it introduces global state into an application. It should also be noted that this pattern reduces the
potential for parallelism within a program, because access to the singleton in a multi-threaded context must be serialised, e.g., by locking. Advocates of dependency
injection
 would regard this as an anti-pattern, mainly due to its use of private and static methods. Some have suggested ways
to break down the singleton pattern using methods such asreflection in languages
such as Java[12][13] or
PHP.[14]

[edit]References

  1. ^ Alex
    Miller. Patterns I hate #1: Singleton, July 2007
  2. ^ Scott
    Densmore. Why singletons are evil, May 2004
  3. ^ Steve
    Yegge. Singletons considered stupid, September 2004
  4. ^ J.B.
    Rainsberger, IBM. Use your singletons wisely, July 2001
  5. ^ Chris
    Reath. Singleton I love you, but you're
    bringing me down
    , October 2008
  6. a b http://googletesting.blogspot.com/2008/11/clean-code-talks-global-state-and.html
  7. ^ Gamma,
    E, Helm, R, Johnson, R, Vlissides, J: "Design Patterns", page 128. Addison-Wesley, 1995
  8. ^ Haggar,
    Peter (1 May 2002). "Double-checked locking and the Singleton pattern".
    IBM.
  9. ^ Coffey,
    Neil (November 16, 2008). "JavaMex tutorials".
    Retrieved April 10, 2012
    .
  10. ^ Pugh,
    Bill
     (November 16, 2008). "The Java Memory Model".
    Retrieved April 27, 2009
    .
  11. ^ Joshua
    Bloch: Effective Java 2nd edition, ISBN 978-0-321-35668-0, 2008, p. 18
  12. ^ Breaking
    the Singleton
    , September 21, 2009
  13. ^ Testing
    a Singleton
    , March 7, 2011
  14. ^ Singleton
    and Multiton with a different approach
    , July 21, 2010

抱歉!评论已关闭.