Please enable JavaScript.
Coggle requires JavaScript to display documents.
Design Pattern, used in conjunction - Coggle Diagram
Design Pattern
Structural patterns
How you compose objects
Store
Adapter
Allows objects with incompatible interfaces to work together. It does this by converting the interface of an existing class (or software) into one that a client (or service) expects.
When
Integration of Legacy Code:
When you need to incorporate legacy code or third-party libraries into your application, the Adapter pattern can be used to bridge the gap between the existing code and the expected interface. By creating an adapter class that implements the expected interface and delegates the calls to the legacy code, you can seamlessly integrate the legacy code into your application without modifying its original implementation.
Reusability of Existing Classes:
If you have existing classes that provide useful functionality but do not conform to the interface required by the client code, the Adapter pattern allows you to adapt those classes by creating an adapter that implements the expected interface. This promotes reusability of existing code and avoids the need for extensive modifications to the original classes.
Interoperability between Components:
When different components or modules in a system use different interfaces, the Adapter pattern can act as a bridge, enabling communication and interaction between them. The adapter class converts the interface of one component into the interface expected by the other component, facilitating their collaboration.
Facade
Provide a simplified interface or entry point to a complex subsystem or set of classes. It encapsulates the complexity of the subsystem behind a single unified interface
When
Simplifying a Complex System:
When you have a subsystem with multiple classes and intricate interactions between them, the Facade pattern can simplify the usage of the system by providing a high-level interface that hides the complexity. The facade acts as a single entry point through which clients can interact with the system without needing to understand or manage the internal details.
Providing a Coherent API:
If you have a set of classes or modules with different interfaces that need to be used together, the Facade pattern can provide a coherent and unified API that clients can work with. It abstracts away the complexities of individual components and provides a consistent interface that simplifies the usage and reduces the learning curve for clients.
Subsystem Decoupling:
The Facade pattern promotes loose coupling between the client code and the subsystem by encapsulating the subsystem's implementation details behind a facade class. This allows for better separation of concerns, as the clients only need to interact with the facade rather than the individual components of the subsystem. It also provides a layer of abstraction that shields clients from changes in the subsystem's internals.
Decorator
when you want to dynamically add or modify behavior to an object at runtime without altering its original implementation
When
Adding Additional Functionality:
When you need to add extra features or behaviors to an object without modifying its original class, the Decorator pattern allows you to wrap the object with one or more decorator classes. Each decorator adds its own functionality while maintaining the original object's interface.
Avoiding Class Explosion:
Instead of creating a large number of subclasses to handle different combinations of behaviors, the Decorator pattern allows you to create small, reusable decorator classes that can be combined to provide various combinations of functionalities. This helps avoid a class explosion and makes the codebase more maintainable.
Runtime Configuration of Objects:
If you want to dynamically configure objects with additional functionalities based on certain conditions or user preferences, the Decorator pattern allows you to add or remove decorators at runtime. This flexibility enables you to adapt the behavior of objects without the need for complex conditional logic or extensive code changes.
Composite
when you want to treat a group of objects in a similar way as a single object. It allows you to create hierarchical structures of objects where both individual objects and groups of objects can be treated uniformly.
Representing Tree-like Structures:
When you have a hierarchical structure that can be represented as a tree, the Composite pattern allows you to treat individual nodes and groups of nodes uniformly. Each node in the tree can be an individual object or a composite object that contains other nodes.
Treating Individual and Group Objects Uniformly:
If you want to apply operations or algorithms to both individual objects and groups of objects without distinguishing between them, the Composite pattern provides a unified interface for interacting with both types of objects. This simplifies the code and promotes a more consistent and flexible design.
Recursive Composition:
When you need to represent recursive compositions where objects can contain other objects of the same type, the Composite pattern is suitable. It allows you to build complex structures by combining simple objects and composite objects recursively.
Bridge pattern
Flyweight
Proxy
Creational patterns
How you create objects.
Singleton
ensure that only one instance of a class is created throughout the lifetime of your application and provide a global point of access to that instance
When
Global Configuration or Resource Management:
If you have a class that manages global application configuration settings or shared resources, such as a database connection pool, thread pool, or cache manager, you can use the Singleton pattern to ensure that there is only one instance of that class. This guarantees that all parts of your application access and modify the same configuration or resource instance consistently.
Logging or Tracing:
Logging and tracing functionalities often require a centralized mechanism to record and manage log entries or trace information across different components of an application. By implementing the logging or tracing functionality as a Singleton, you can easily access the same instance from anywhere in your application and maintain a centralized log or trace store.
Caching:
If you need to cache data in memory to improve performance, a Singleton cache manager can be used to store and retrieve cached data. This ensures that all parts of your application access the same cache instance, allowing for efficient data sharing and reducing redundant calculations or network requests.
Access to Shared Resources:
In certain cases, multiple objects may need access to a shared resource, such as a database, file system, or hardware device. By implementing the access to that shared resource as a Singleton, you can coordinate and manage the access to the resource, ensuring that it is used consistently and avoiding conflicts or unnecessary resource duplication.
Factory
provides an interface or base class for creating objects of different types without exposing the creation logic
When
Object Creation with Complex Logic:
If the creation of an object involves complex initialization or involves the selection of a specific implementation based on certain conditions, the Factory pattern can encapsulate this logic in a separate factory class. This allows the client code to request objects without being aware of the intricate details of the creation process.
Encapsulation of Object Creation:
By delegating object creation to a factory class, you can encapsulate the creation logic in one place. This promotes better code organization and adheres to the principle of separating concerns, as the client code only needs to interact with the factory rather than creating objects directly.
Creating Objects with a Common Interface:
When you have a family of related classes that implement a common interface or inherit from a common base class, the Factory pattern provides a way to create instances of these classes without exposing their concrete types. This enables polymorphism and allows for easier extensibility and maintenance.
Builder
to construct complex objects step by step
When
The construction of an object involves multiple steps or parameters:
If an object requires a complex construction process with many optional or mandatory parameters, using a constructor with a long parameter list can become confusing and error-prone. The Builder pattern provides a cleaner and more readable way to construct such objects by dividing the construction process into separate steps.
You want to create immutable objects:
If you want to create immutable objects where the state cannot be modified after construction, the Builder pattern is a good choice. The Builder allows you to set the values of the object's properties during construction, and once the object is built, it remains immutable.
You need to create different representations of an object:
The Builder pattern can be used to construct different variations or configurations of an object. By using different builders, you can easily create different representations or flavors of the same object, without polluting the object's class with a multitude of constructors or configuration methods.
You want to improve readability and maintainability:
The Builder pattern enhances the readability of code by providing clear and descriptive method chaining. It also simplifies maintenance by separating the construction logic from the client code, making it easier to modify or extend the construction process without impacting the client code.
Abstract Factory
Prototype
Object Pool
Behavioral patterns
How you coordinate object interactions
Observer
When establishing a one-to-many relationship between objects, When one object changes state, its dependents get a notification and updates automatically
Framework
RxJava
RxAndroid
RxKotlin
Command
Encapsulates a request as an object and issue requests without knowing the receiver. provides a way to decouple the sender and receiver
Greenrobot’s EventBus framwork
When
Need to decouple the request from the object that makes the request.
Need to allow clients to execute requests at different times.
Strategy
when you have a family of algorithms or behaviors that
can be interchanged dynamically at runtime
. It allows you to encapsulate each algorithm or behavior into separate classes and select the appropriate strategy based on the specific context or requirements.
State
Allows an object to altert its behavior accordingly when its internal state changes
by encapsulating each state as a separate class and delegating the behavior to the current state object
When
when an object has many state and object's behavior needs to change dynamically based on its internal state
Inversion of Control (IoC)
Dependency Injection
used in conjunction