diff --git a/crtp/README.md b/crtp/README.md index cfb438c06..b767065ec 100644 --- a/crtp/README.md +++ b/crtp/README.md @@ -1,5 +1,5 @@ --- -title: CRTP +title: Curiously Recurring Template Pattern language: en category: Structural tag: @@ -10,10 +10,11 @@ tag: ## Also known as +* CRTP +* Mixin Inheritance * Recursive Type Bound * Recursive Generic * Static Polymorphism -* Mixin Inheritance ## Intent diff --git a/singleton/README.md b/singleton/README.md index bb94d5375..ca8467cb7 100644 --- a/singleton/README.md +++ b/singleton/README.md @@ -3,9 +3,15 @@ title: Singleton category: Creational language: en tag: - - Gang of Four + - Gang of Four + - Instantiation + - Resource management --- +## Also known as + +* Single Instance + ## Intent Ensure a class only has one instance, and provide a global point of access to it. @@ -14,8 +20,7 @@ Ensure a class only has one instance, and provide a global point of access to it Real-world example -> There can only be one ivory tower where the wizards study their magic. The same enchanted ivory -> tower is always used by the wizards. The ivory tower here is a singleton. +> A real-world analogy for the Singleton pattern is a government issuing a passport. In a country, each citizen can only be issued one valid passport at a time. The passport office ensures that no duplicate passports are issued to the same person. Whenever a citizen needs to travel, they must use this single passport, which serves as the unique, globally recognized identifier for their travel credentials. This controlled access and unique instance management in the real world mirrors how the Singleton pattern controls the instantiation of a class in software. In plain words @@ -23,9 +28,7 @@ In plain words Wikipedia says -> In software engineering, the singleton pattern is a software 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. +> In software engineering, the singleton pattern is a software 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. **Programmatic Example** @@ -57,7 +60,7 @@ enumIvoryTower2=com.iluwatar.singleton.EnumIvoryTower@1221555852 ## Class diagram -![alt text](./etc/singleton.urm.png "Singleton pattern class diagram") +![Singleton](./etc/singleton.urm.png "Singleton pattern class diagram") ## Applicability @@ -66,29 +69,42 @@ Use the Singleton pattern when * There must be exactly one instance of a class, and it must be accessible to clients from a well-known access point * When the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying their code -Some typical use cases for the Singleton - -* The logging class -* Managing a connection to a database -* File manager - ## Known uses +* The logging class +* Configuration classes in many applications +* Connection pools +* File manager * [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29) * [java.awt.Desktop#getDesktop()](http://docs.oracle.com/javase/8/docs/api/java/awt/Desktop.html#getDesktop--) * [java.lang.System#getSecurityManager()](http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getSecurityManager--) - ## Consequences -* Violates Single Responsibility Principle (SRP) by controlling their creation and lifecycle. -* Encourages using a globally shared instance which prevents an object and resources used by this object from being deallocated. -* Creates tightly coupled code. The clients of the Singleton become difficult to test. -* Makes it almost impossible to subclass a Singleton. +Benefits: + +* Controlled access to the single instance. +* Reduced namespace pollution. +* Allows refinement of operations and representation. +* Permits a variable number of instances (more than one, if desired). +* More flexible than class operations. + +Trade-offs: + +* Difficult to test due to global state. +* Potentially more complex lifecycle management. +* Can introduce bottlenecks if used in a concurrent context without careful synchronization. + +## Related Patterns + +* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/): Often used to ensure a class only has one instance. +* [Factory Method](https://java-design-patterns.com/patterns/factory-method/): Singleton pattern can be implemented using a Factory Method to encapsulate the creation logic. +* [Prototype](https://java-design-patterns.com/patterns/prototype/): Avoids the need to create instances, can work alongside Singleton to manage unique instances. ## Credits -* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) -* [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0134685997&linkCode=as2&tag=javadesignpat-20&linkId=4e349f4b3ff8c50123f8147c828e53eb) -* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) -* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) +* [Effective Java](https://amzn.to/4cGk2Jz) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq) +* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3yhh525) +* [Refactoring to Patterns](https://amzn.to/3VOO4F5) diff --git a/singleton/src/main/java/com/iluwatar/singleton/App.java b/singleton/src/main/java/com/iluwatar/singleton/App.java index 8d7946cae..1b14f9ad7 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/App.java +++ b/singleton/src/main/java/com/iluwatar/singleton/App.java @@ -89,7 +89,7 @@ public class App { LOGGER.info("enumIvoryTower1={}", enumIvoryTower1); LOGGER.info("enumIvoryTower2={}", enumIvoryTower2); - // double checked locking + // double-checked locking var dcl1 = ThreadSafeDoubleCheckLocking.getInstance(); LOGGER.info(dcl1.toString()); var dcl2 = ThreadSafeDoubleCheckLocking.getInstance(); diff --git a/singleton/src/main/java/com/iluwatar/singleton/BillPughImplementation.java b/singleton/src/main/java/com/iluwatar/singleton/BillPughImplementation.java index ba6638618..a93e3a656 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/BillPughImplementation.java +++ b/singleton/src/main/java/com/iluwatar/singleton/BillPughImplementation.java @@ -45,7 +45,7 @@ public final class BillPughImplementation { } /** - * The InstanceHolder is a static inner class and it holds the Singleton instance. + * The InstanceHolder is a static inner class, and it holds the Singleton instance. * It is not loaded into memory until the getInstance() method is called. */ private static class InstanceHolder { diff --git a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java index e409432a1..fa307b6f6 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java +++ b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java @@ -62,7 +62,7 @@ public final class ThreadSafeDoubleCheckLocking { // Check if singleton instance is initialized. // If it is initialized then we can return the instance. if (result == null) { - // It is not initialized but we cannot be sure because some other thread might have + // It is not initialized, but we cannot be sure because some other thread might have // initialized it in the meanwhile. // So to make sure we need to lock on an object to get mutual exclusion. synchronized (ThreadSafeDoubleCheckLocking.class) { @@ -72,7 +72,7 @@ public final class ThreadSafeDoubleCheckLocking { // just like the previous null check. result = instance; if (result == null) { - // The instance is still not initialized so we can safely + // The instance is still not initialized, so we can safely // (no other thread can enter this zone) // create an instance and make it our singleton instance. result = new ThreadSafeDoubleCheckLocking(); diff --git a/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java b/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java index 5fb6c3f8e..69b1c9e37 100644 --- a/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java +++ b/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java @@ -85,7 +85,7 @@ abstract class SingletonTest { * Test singleton instance in a concurrent setting. */ @Test - void testMultipleCallsReturnTheSameObjectInDifferentThreads() throws Exception { + void testMultipleCallsReturnTheSameObjectInDifferentThreads() { assertTimeout(ofMillis(10000), () -> { // Create 10000 tasks and inside each callable instantiate the singleton class final var tasks = IntStream.range(0, 10000) @@ -96,7 +96,7 @@ abstract class SingletonTest { final var executorService = Executors.newFixedThreadPool(8); final var results = executorService.invokeAll(tasks); - // wait for all of the threads to complete + // wait for all the threads to complete final var expectedInstance = this.singletonInstanceMethod.get(); for (var res : results) { final var instance = res.get();