Singleton
-o0O0o-
How to ensure that only one (or a limited number) of instances of a class can exist?
-o0O0o-
UML Model File:
Model Format
Visual Paradigm
Advantages
- It is a well-established way to control object creation
- It can be adapted to allow the creation and access of a limited number of instances
Disadvantages
- It should not be overused, as it is similar to a global variable (although it does not pollute the global namespace)
- Singleton instance creation and access must be serialized in multithreaded applications
- Introduces a global state that makes unit testing more difficult
Code Examples
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
/* * Normally, we adopt a “lazy instantiation” strategy, in which we * do not create the instance until it is required for the first * time. */ class Singular { private static Singular theInstance; ... // attribute declaration /* * Here, we declare the constructor as private so that it can not be * invoked from outside the class (that is, we prevent client classes * creating instances by using “new”). */ private Singular(...) { ... // attribute initialization } /* * The “getSingularInstance” is a factory method that is in charge of * returning the instance, and also of creating it in the first place. */ public static Singular getSingularInstance() { if (theInstance == null) theInstance = new Singular(...); return theInstance; } // instance methods } /* * If we use multi-threading and we adopt a “lazy instantiation” strategy, * we may have situations in which two calls to “getSingularInstance” * arrive at the same time resulting in two instances being created. * To avoid this, we must use sinchronization in the call to this method. */ class Singular { private static Singular theInstance; ... // attribute declaration private Singular(...) { ... // attribute initialization } /* * The “getSingularInstance” is now declared as synchronized, which * prevents problems with multi-threading. */ public static synchronized Singular getSingularInstance() { if (theInstance == null) theInstance = new Singular(...); return theInstance; } // instance methods } /* * If the performance is important, which is seldom the case, the use * of synchronization (which is slow) may be limited to using it only * for the creation of theInstance and not in subsequent calls to the * method. To do this, we must declare the theInstance variable as * volatile, in order to inform the compiler that it must be always be * read from the main memory (avoiding caching). */ private static volatile Singular theInstance; /* * …and we must also we must modify the getSingularInstance method as * shown in the following code. Please note that it is only when we need * to create the instance we enter the synchronized section, and in that * case we must check again inside that section. For this reason, this * approach is called double-check locking. */ public static Singular getSingularInstance() { if (theInstance == null) { synchronized(Singular.class) { if (theInstance == null) { theInstance = new Singular(...); } } } return theInstance; } /* * Alternatively, we may adopt an “early instantiation” strategy, in which * we create the instance at the time of classloading. */ class Singular { private static Singular theInstance = new Singular(...); ... // attribute declaration private Singular(...) { ... // attribute initialization } /* * The “getSingularInstance” is simpler in this case since we do not * need to check the existence of the instance. */ public static Singular getSingularInstance() { return theInstance; } // instance methods } |