GoF
Proxy
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 |
/** * Normally, we adopt a "lazy instantiation" strategy for the RealSubject, * creating it only when it is actually required. */ class RealSubject { ... // RealSubject attribute declaration public RealSubject(...) { ... // RealSubject attribute initialization } public void request() { ... // Real implementation of the request method } } /** * The Proxy class contains a reference that lets the proxy access the real subject. * Proxy also implements the same interface as the real subject and delegates all the work to the real subject. */ class Proxy { private static RealSubject realSubject; ... // Proxy specific attribute declaration public Proxy(...) { ... // Proxy specific initialization } /** * The "request" method is used to access the RealSubject's request method. * This could involve additional logic such as lazy instantiation, access control, or logging. */ public void request() { if (realSubject == null) { realSubject = new RealSubject(...); } ... // Additional logic before delegating the request realSubject.request(); ... // Additional logic after delegating the request } } /** * If we are concerned with thread safety when using multi-threading, we need to ensure * that our Proxy class handles simultaneous calls properly, especially during instantiation of the RealSubject. */ class Proxy { private static volatile RealSubject realSubject; ... // Proxy specific attribute declaration public Proxy(...) { ... // Proxy specific initialization } /** * We use synchronized blocks inside the request method to ensure that RealSubject is * instantiated only once, even with concurrent access. */ public static void request() { if (realSubject == null) { synchronized (Proxy.class) { if (realSubject == null) { realSubject = new RealSubject(...); } } } realSubject.request(); } } /** * Alternatively, we may use an "early instantiation" strategy for RealSubject, creating it * at the time of Proxy class loading. This simplifies the request method as it no longer needs * to check if RealSubject exists. */ class Proxy { private static final RealSubject realSubject = new RealSubject(...); ... // Proxy specific attribute declaration public Proxy(...) { ... // Proxy specific initialization } /** * The "request" method simply delegates the request to the RealSubject. */ public void request() { realSubject.request(); } } |
Singleton
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 } |