init
This commit is contained in:
commit
c5cd492449
475 changed files with 27928 additions and 0 deletions
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Abstract Factory Pattern
|
||||
## **Description:**
|
||||
The Abstract Factory Pattern is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. It is often used to ensure that a system is compatible with multiple families of objects, allowing you to switch between these families without changing the client code.
|
||||
|
||||
**How it's Used:**
|
||||
|
||||
1. **Abstract Factory Interface**: Define an abstract factory interface that declares a set of creation methods for creating abstract product objects. Each method corresponds to a different type of product.
|
||||
|
||||
2. **Concrete Factories**: Create concrete factory classes that implement the abstract factory interface. Each concrete factory is responsible for creating a specific family of related products.
|
||||
|
||||
3. **Abstract Product Interface**: Define an abstract product interface that declares the common methods that concrete product classes must implement. Each product family will have its own set of product interfaces.
|
||||
|
||||
4. **Concrete Products**: Create concrete product classes that implement the abstract product interfaces. These classes provide specific implementations for the products within each family.
|
||||
|
||||
5. **Client Code**: In the client code, use the abstract factory to create families of objects. Clients interact with the abstract factory and abstract product interfaces rather than directly with concrete classes.
|
||||
|
||||
|
||||
## **Example:**
|
||||
Let's say you're building a user interface (UI) framework that can be used on both desktop and mobile platforms. You want to ensure that UI components like buttons and text fields are consistent within each platform but can be easily switched between platforms. Here's how the Abstract Factory Pattern can be applied:
|
||||
|
||||
- **Abstract Factory Interface**: Define an `AbstractUIFactory` interface with methods like `createButton` and `createTextField`.
|
||||
|
||||
- **Concrete Factories**: Create two concrete factory classes: `DesktopUIFactory` and `MobileUIFactory`, both implementing the `AbstractUIFactory`. The `DesktopUIFactory` creates desktop-style UI components, while the `MobileUIFactory` creates mobile-style UI components.
|
||||
|
||||
- **Abstract Product Interfaces**: Define abstract product interfaces like `Button` and `TextField` that specify the methods these UI components should have.
|
||||
|
||||
- **Concrete Products**: Create concrete product classes like `DesktopButton`, `MobileButton`, `DesktopTextField`, and `MobileTextField`, each implementing the corresponding abstract product interfaces.
|
||||
|
||||
- **Client Code**: In your application, use the appropriate factory (either `DesktopUIFactory` or `MobileUIFactory`) to create UI components. For example:
|
||||
|
||||
|
||||
```java
|
||||
AbstractUIFactory factory = getUIFactoryForPlatform();
|
||||
Button button = factory.createButton();
|
||||
TextField textField = factory.createTextField();
|
||||
```
|
||||
|
||||
By using the Abstract Factory Pattern, you can switch between desktop and mobile UI components seamlessly by changing the factory you use, without modifying the client code.
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Builder Pattern
|
||||
|
||||
## **Description:**
|
||||
The Builder Pattern is a creational design pattern used to construct a complex object step by step. It separates the construction of an object from its representation, allowing you to create different variations of the same object with a clear and consistent API. This pattern is particularly useful when an object has many optional components or configuration settings.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Builder Interface**: Define an abstract builder interface that declares methods for constructing different parts of the complex object. These methods should cover all possible configurations.
|
||||
2. **Concrete Builders**: Create concrete builder classes that implement the builder interface. Each concrete builder is responsible for building a specific variant of the complex object.
|
||||
3. **Product**: Define the complex object (the product) that you want to create. This object should have a way to accept values or components set by the builder.
|
||||
4. **Director (Optional)**: You can create a director class (optional) that orchestrates the construction process using a specific builder. The director simplifies client code by providing a higher-level interface to construct the object.
|
||||
5. **Client Code**: In your application, use the builder to construct the complex object step by step. You can chain method calls together for a more fluent and readable construction process.
|
||||
|
||||
## **Example:**
|
||||
Consider building a `Computer` object with various optional components such as a processor, memory, storage, and graphics card. Here's how the Builder Pattern can be applied:
|
||||
- **Builder Interface**: Define an `ComputerBuilder` interface with methods like `setProcessor`, `setMemory`, `setStorage`, and `setGraphicsCard`.
|
||||
- **Concrete Builders**: Create concrete builder classes like `GamingComputerBuilder` and `OfficeComputerBuilder`, both implementing the `ComputerBuilder` interface. Each builder knows how to construct a specific type of computer.
|
||||
- **Product**: Define the `Computer` class with fields for processor, memory, storage, and graphics card, and a constructor to initialize these fields.
|
||||
- **Director (Optional)**: Create a `ComputerDirector` class that takes a `ComputerBuilder` as a parameter. The director can provide higher-level methods like `buildGamingComputer` or `buildOfficeComputer`.
|
||||
- **Client Code**: In your application, use the builder to construct a computer with the desired components:
|
||||
|
||||
```java
|
||||
ComputerBuilder builder = new GamingComputerBuilder();
|
||||
Computer gamingComputer = builder.setMemory(16).buildComputer();
|
||||
```
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Dependency Injection
|
||||
|
||||
## **Description:**
|
||||
Dependency Injection (DI) is a design pattern used in software development to achieve Inversion of Control (IoC). It helps manage the dependencies between components or classes by externalizing the dependencies and injecting them rather than having the components create their own dependencies. This promotes loose coupling, testability, and flexibility in your code.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Dependency**: Identify the dependencies that a class or component needs to function properly. These dependencies can be other objects, services, or configurations.
|
||||
2. **Injection Mechanism**: Create a mechanism to provide these dependencies to the class that needs them. This can be done in several ways, such as constructor injection, setter injection, or method injection.
|
||||
3. **Injection Container (Optional)**: In larger applications, you may use an injection container or a framework (e.g., Spring, Guice) to manage and automatically inject dependencies. These containers can handle the creation and wiring of objects.
|
||||
4. **Client Code**: In your application, create instances of the classes and inject the required dependencies. This can be done manually or by using an injection container.
|
||||
|
||||
## **Example:**
|
||||
Consider a simple Java application where you have a `UserService` class that depends on a `UserRepository` to retrieve user data from a database. Here's how Dependency Injection can be applied:
|
||||
|
||||
- **Identify Dependencies**: Recognize that `UserService` depends on `UserRepository`.
|
||||
- **Injection Mechanism**: Use constructor injection to inject the `UserRepository` dependency into the `UserService` class.
|
||||
|
||||
```java
|
||||
public class UserService {
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public UserService(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
// Use userRepository to perform user-related operations
|
||||
}
|
||||
```
|
||||
|
||||
- **Client Code**: In your application code, create instances of `UserRepository` and `UserService`, and inject the `UserRepository` into the `UserService`.
|
||||
|
||||
```java
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
UserRepository userRepository = new UserRepository(); // or use an injection container
|
||||
UserService userService = new UserService(userRepository);
|
||||
|
||||
// Use the userService to work with users
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
By using Dependency Injection, you've decoupled the `UserService` and `UserRepository`, making it easier to replace or test these components independently. You can change the `UserRepository` implementation or switch to a mock repository for testing without modifying the `UserService` class. This promotes modularity and maintainability in your code.
|
|
@ -0,0 +1,87 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Factory Method Pattern
|
||||
|
||||
## **Description:**
|
||||
The Factory Method Pattern is a creational design pattern that defines an interface for creating objects but allows subclasses to alter the type of objects that will be created. It provides a way to delegate the responsibility of instantiating objects to subclasses, promoting flexibility and extensibility in your code.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Creator Interface or Abstract Class**: Define an abstract class or interface, often referred to as the "creator," that declares a method for creating objects. This method is the factory method.
|
||||
2. **Concrete Creators**: Create concrete subclasses of the creator class, each of which implements the factory method. These subclasses decide which class of objects to create and return.
|
||||
3. **Product**: Define an abstract product class or interface that represents the type of object created by the factory method.
|
||||
4. **Concrete Products**: Create concrete classes that implement the product interface. Each concrete product represents a specific variant or type of object.
|
||||
5. **Client Code**: In your application, use the creator class and its factory method to create objects. The client code typically works with the creator interface or abstract class rather than concrete classes.
|
||||
|
||||
## **Example:**
|
||||
Imagine you are developing a document processing application that can handle different types of documents, such as `TextDocument` and `SpreadsheetDocument`. Here's how the Factory Method Pattern can be applied:
|
||||
|
||||
- **Creator Interface or Abstract Class**: Define an abstract class called `DocumentCreator` with a factory method named `createDocument`.
|
||||
```java
|
||||
public abstract class DocumentCreator {
|
||||
public abstract Document createDocument();
|
||||
}
|
||||
```
|
||||
- **Concrete Creators**: Create concrete subclasses of `DocumentCreator`, such as `TextDocumentCreator` and `SpreadsheetDocumentCreator`. Each subclass implements the `createDocument` method to return a specific type of document
|
||||
```java
|
||||
public class TextDocumentCreator extends DocumentCreator {
|
||||
@Override
|
||||
public Document createDocument() {
|
||||
return new TextDocument();
|
||||
}
|
||||
}
|
||||
|
||||
public class SpreadsheetDocumentCreator extends DocumentCreator {
|
||||
@Override
|
||||
public Document createDocument() {
|
||||
return new SpreadsheetDocument();
|
||||
}
|
||||
}
|
||||
```
|
||||
- **Product**: Define an abstract `Document` class or interface that represents the common operations for documents.
|
||||
```java
|
||||
public abstract class Document {
|
||||
public abstract void open();
|
||||
public abstract void save();
|
||||
}
|
||||
```
|
||||
- **Concrete Products**: Create concrete classes like `TextDocument` and `SpreadsheetDocument` that implement the `Document` interface with specific implementations.
|
||||
```java
|
||||
public class TextDocument extends Document {
|
||||
@Override
|
||||
public void open() {
|
||||
System.out.println("Opening Text Document");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
System.out.println("Saving Text Document");
|
||||
}
|
||||
}
|
||||
|
||||
public class SpreadsheetDocument extends Document {
|
||||
@Override
|
||||
public void open() {
|
||||
System.out.println("Opening Spreadsheet Document");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
System.out.println("Saving Spreadsheet Document");
|
||||
}
|
||||
}
|
||||
```
|
||||
- **Client Code**: In your application, use the creator classes and their factory methods to create documents without knowing the concrete document classes:
|
||||
```java
|
||||
DocumentCreator textDocumentCreator = new TextDocumentCreator();
|
||||
Document textDocument = textDocumentCreator.createDocument();
|
||||
textDocument.open();
|
||||
textDocument.save();
|
||||
|
||||
DocumentCreator spreadsheetDocumentCreator = new SpreadsheetDocumentCreator();
|
||||
Document spreadsheetDocument = spreadsheetDocumentCreator.createDocument();
|
||||
spreadsheetDocument.open();
|
||||
spreadsheetDocument.save();
|
||||
```
|
||||
|
||||
The Factory Method Pattern allows you to extend your application with new document types by creating additional concrete creators and products without modifying existing client code, promoting code reuse and maintainability.
|
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Lazy Instantiation
|
||||
|
||||
## **Description:**
|
||||
Lazy Instantiation is a design pattern that defers the creation of an object until it is actually needed. This pattern is particularly useful when creating or initializing an object is expensive in terms of time or resources, and you want to postpone it until the last possible moment to improve performance or save resources.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Identify Expensive Objects**: Determine which objects or resources in your application are expensive to create or initialize.
|
||||
2. **Initialization on First Use**: Instead of creating these objects when the application starts, initialize them only when they are first requested by a client or when they are needed for a specific task.
|
||||
3. **Lazy Initialization Mechanism**: Implement a mechanism to perform lazy initialization. Common techniques include using a null check, a flag, or a synchronized block to ensure that the object is created only once and when it's required.
|
||||
4. **Client Code**: In your application, access or request the object as needed. The lazy initialization mechanism will ensure that the object is created the first time it's requested and reused for subsequent requests.
|
||||
|
||||
## **Example:**
|
||||
Consider an application that manages a large collection of images, and loading each image into memory is resource-intensive. To save resources and improve performance, you can implement Lazy Instantiation for image loading:
|
||||
|
||||
- **Identify Expensive Objects**: Recognize that loading images into memory is resource-intensive.
|
||||
- **Lazy Initialization Mechanism**: Create a class called `ImageLoader` that manages the loading of images. In this class, implement a lazy initialization mechanism for loading images on-demand.
|
||||
```java
|
||||
public class ImageLoader {
|
||||
private Map<String, Image> loadedImages = new HashMap<>();
|
||||
|
||||
public Image getImage(String filename) {
|
||||
if (!loadedImages.containsKey(filename)) {
|
||||
// Load the image from disk or a remote source
|
||||
Image image = loadImageFromFile(filename);
|
||||
loadedImages.put(filename, image);
|
||||
}
|
||||
return loadedImages.get(filename);
|
||||
}
|
||||
|
||||
private Image loadImageFromFile(String filename) {
|
||||
// Code to load the image from disk or a remote source
|
||||
// ...
|
||||
return new Image(filename);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Client Code**: In your application, when you need to display an image, use the `ImageLoader` to obtain the image. The `ImageLoader` will load the image from the source only when requested and cache it for future use:
|
||||
```java
|
||||
ImageLoader imageLoader = new ImageLoader();
|
||||
Image image1 = imageLoader.getImage("image1.jpg"); // Loaded when first requested
|
||||
Image image2 = imageLoader.getImage("image2.jpg"); // Loaded when first requested
|
||||
|
||||
// Later in the application
|
||||
Image image3 = imageLoader.getImage("image1.jpg"); // Reused from cache
|
||||
```
|
||||
|
||||
By applying Lazy Instantiation in this example, you ensure that images are loaded into memory only when needed, conserving resources and improving the application's responsiveness. The images are cached for reuse, further enhancing performance when the same image is requested multiple times.
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Multiton Pattern
|
||||
|
||||
## **Description:**
|
||||
The Multiton Pattern is a variation of the [Singleton Pattern](Singleton%20Pattern.md) that ensures a class has only a limited number of instances, where each instance is uniquely identified by a key. Unlike the [Singleton Pattern](Singleton%20Pattern.md), which allows only one instance of a class, the Multiton Pattern allows multiple instances, each associated with a specific key.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Multiton Class**: Define a class that you want to limit the number of instances for. This class will manage multiple instances, each associated with a unique key.
|
||||
2. **Private Constructor**: Ensure that the constructor of the class is private to prevent external instantiation.
|
||||
3. **Internal Registry**: Create an internal registry (usually a dictionary or map) within the class to store instances associated with their respective keys.
|
||||
4. **Factory Method**: Implement a factory method or a static method within the class to create or retrieve instances based on keys.
|
||||
5. **Use Keys**: When you need an instance of the class, provide a key to the factory method. The method will either create a new instance or return an existing instance associated with the provided key.
|
||||
|
||||
## **Example:**
|
||||
Let's say you're creating a logging system for your application, and you want to have separate loggers for different modules. You can use the Multiton Pattern to ensure that each module has its own logger:
|
||||
|
||||
- **Multiton Class**: Define a `Logger` class.
|
||||
```java
|
||||
public class Logger {
|
||||
private static final Map<String, Logger> instances = new HashMap<>();
|
||||
|
||||
private Logger() {
|
||||
// Private constructor
|
||||
}
|
||||
|
||||
public static Logger getInstance(String module) {
|
||||
if (!instances.containsKey(module)) {
|
||||
instances.put(module, new Logger());
|
||||
}
|
||||
return instances.get(module);
|
||||
}
|
||||
|
||||
public void log(String message) {
|
||||
// Logging implementation
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Private Constructor**: Ensure that the constructor of the `Logger` class is private to prevent external instantiation.
|
||||
- **Internal Registry**: Use a `Map<String, Logger>` (`instances`) to store logger instances associated with their respective modules (keys).
|
||||
- **Factory Method**: Implement a `getInstance` static method that takes a `module` parameter and returns a `Logger` instance associated with that module. If an instance for the module does not exist, create one and store it in the registry.
|
||||
- **Use Keys**: In your application, when you need a logger for a specific module, use the `Logger.getInstance(module)` method to obtain or create the logger instance.
|
||||
```java
|
||||
Logger loggerA = Logger.getInstance("ModuleA");
|
||||
Logger loggerB = Logger.getInstance("ModuleB");
|
||||
|
||||
loggerA.log("Log message for ModuleA");
|
||||
loggerB.log("Log message for ModuleB");
|
||||
```
|
||||
|
||||
By using the Multiton Pattern, you ensure that each module gets its own unique logger instance, identified by the module name. This allows you to have separate loggers for different parts of your application while keeping the logging code centralized and manageable.
|
|
@ -0,0 +1,87 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Object Pool Pattern
|
||||
|
||||
## **Description:**
|
||||
The Object Pool Pattern is a creational design pattern that manages a pool of reusable objects to avoid the overhead of creating and destroying objects frequently. It provides a way to efficiently manage and reuse a limited number of instances of a class, especially when creating and initializing these instances is resource-intensive.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Create a Pool**: Create a pool of objects that you want to reuse. These objects could be expensive to create, initialize, or destroy.
|
||||
2. **Initialization**: Initialize the pool by creating a predefined number of objects and adding them to the pool.
|
||||
3. **Object Request**: When an object is needed, instead of creating a new one, request an object from the pool.
|
||||
4. **Object Return**: After using an object, return it to the pool for reuse. This is typically done by marking the object as available.
|
||||
5. **Manage Pool Size (Optional)**: Implement a mechanism to ensure that the pool doesn't exceed a maximum size. If the pool is empty and an object is requested, you can decide whether to create a new object or wait until an object becomes available.
|
||||
|
||||
## **Example:**
|
||||
Consider a scenario where you have a web server that handles incoming HTTP requests. Creating a new connection to a database for each request can be expensive. You can use the Object Pool Pattern to manage a pool of database connections efficiently:
|
||||
|
||||
- **Create a Pool**: Define a `DatabaseConnection` class to represent database connections.
|
||||
- **Initialization**: Create and initialize a fixed number of database connections when the application starts. Add these connections to the pool.
|
||||
- **Object Request**: When a new HTTP request arrives and requires a database connection, request a connection from the pool.
|
||||
- **Object Return**: After handling the request, return the database connection to the pool for reuse.
|
||||
- **Manage Pool Size (Optional)**: Implement mechanisms to control the pool size, such as setting a maximum number of connections or waiting for a connection to become available if the pool is empty.
|
||||
|
||||
|
||||
Here's a simplified example in Java:
|
||||
```java
|
||||
public class DatabaseConnection {
|
||||
private boolean inUse;
|
||||
|
||||
public DatabaseConnection() {
|
||||
// Initialize the database connection
|
||||
// ...
|
||||
}
|
||||
|
||||
public void markInUse() {
|
||||
inUse = true;
|
||||
}
|
||||
|
||||
public void markAvailable() {
|
||||
inUse = false;
|
||||
}
|
||||
|
||||
public boolean isInUse() {
|
||||
return inUse;
|
||||
}
|
||||
}
|
||||
|
||||
public class ConnectionPool {
|
||||
private List<DatabaseConnection> connections;
|
||||
|
||||
public ConnectionPool(int poolSize) {
|
||||
connections = new ArrayList<>();
|
||||
for (int i = 0; i < poolSize; i++) {
|
||||
connections.add(new DatabaseConnection());
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized DatabaseConnection getConnection() {
|
||||
for (DatabaseConnection connection : connections) {
|
||||
if (!connection.isInUse()) {
|
||||
connection.markInUse();
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
return null; // or create a new connection if allowed
|
||||
}
|
||||
|
||||
public synchronized void releaseConnection(DatabaseConnection connection) {
|
||||
connection.markAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
// In your web server code
|
||||
ConnectionPool pool = new ConnectionPool(10); // Initialize a pool with 10 database connections
|
||||
|
||||
// When handling an HTTP request
|
||||
DatabaseConnection connection = pool.getConnection();
|
||||
if (connection != null) {
|
||||
// Use the connection for database operations
|
||||
// ...
|
||||
// Return the connection to the pool when done
|
||||
pool.releaseConnection(connection);
|
||||
}
|
||||
```
|
||||
|
||||
By using the Object Pool Pattern, you can efficiently manage and reuse database connections, reducing the overhead of creating and destroying connections for each HTTP request. This can improve the performance and resource usage of your web server.
|
|
@ -0,0 +1,79 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Prototype Pattern
|
||||
|
||||
## **Description:**
|
||||
The Prototype Pattern is a creational design pattern that allows you to create new objects by copying an existing object, known as the "prototype." It is particularly useful when the cost of creating an object is more expensive or complex than copying it, or when you want to create new objects with the same initial state as an existing one.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Prototype Interface or Abstract Class**: Define a common interface or abstract class for all concrete prototypes. This interface should include a method for cloning the object.
|
||||
2. **Concrete Prototypes**: Create concrete classes that implement the prototype interface or extend the prototype abstract class. These classes define the specific properties and behaviors of the objects you want to clone.
|
||||
3. **Clone Method**: Implement the clone method in each concrete prototype class. This method should create a new instance of the same class and copy the state from the current instance to the new one.
|
||||
4. **Client Code**: In your application, use the prototype to create new objects by cloning the prototype object. The client code should not be responsible for creating objects from scratch but should rely on the prototype to provide new instances.
|
||||
|
||||
## **Example:**
|
||||
Let's say you are developing a game where characters can be customized with various attributes, such as name, appearance, and abilities. Instead of creating each character from scratch, you can use the Prototype Pattern to clone a prototype character with default attributes and customize the clones as needed:
|
||||
|
||||
- **Prototype Interface or Abstract Class**: Define a `Character` interface or abstract class that includes a `clone` method.
|
||||
```java
|
||||
public interface Character {
|
||||
Character clone();
|
||||
void customize(String name, String appearance, String abilities);
|
||||
void displayInfo();
|
||||
}
|
||||
```
|
||||
|
||||
- **Concrete Prototypes**: Create concrete character classes that implement the `Character` interface or extend the `Character` abstract class. Each class represents a specific type of character.
|
||||
```java
|
||||
public class Warrior implements Character {
|
||||
private String name;
|
||||
private String appearance;
|
||||
private String abilities;
|
||||
|
||||
public Warrior() {
|
||||
// Default attributes for a warrior
|
||||
this.name = "Warrior";
|
||||
this.appearance = "Strong and armored";
|
||||
this.abilities = "Melee combat skills";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Character clone() {
|
||||
Warrior clone = new Warrior();
|
||||
clone.customize(this.name, this.appearance, this.abilities);
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(String name, String appearance, String abilities) {
|
||||
this.name = name;
|
||||
this.appearance = appearance;
|
||||
this.abilities = abilities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayInfo() {
|
||||
System.out.println("Character: " + name);
|
||||
System.out.println("Appearance: " + appearance);
|
||||
System.out.println("Abilities: " + abilities);
|
||||
}
|
||||
}
|
||||
|
||||
// Create similar classes for other character types (e.g., Mage, Rogue)
|
||||
```
|
||||
|
||||
- **Client Code**: In your game code, use the prototype to create new character instances and customize them as needed:
|
||||
```java
|
||||
Character prototype = new Warrior();
|
||||
Character warrior1 = prototype.clone();
|
||||
warrior1.customize("Sir Lancelot", "Shiny armor", "Swordsmanship");
|
||||
|
||||
Character warrior2 = prototype.clone();
|
||||
warrior2.customize("Lady Guinevere", "Elegant armor", "Archery");
|
||||
|
||||
warrior1.displayInfo();
|
||||
warrior2.displayInfo();
|
||||
```
|
||||
|
||||
By using the Prototype Pattern, you can create new character instances by cloning the prototype, customizing them for different characters in your game, and displaying their individual attributes. This pattern promotes code reusability and flexibility when creating objects with similar initial states.
|
57
technology/programming/patterns/creational/RAII Pattern.md
Normal file
57
technology/programming/patterns/creational/RAII Pattern.md
Normal file
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Resource Acquisition Is Initialization (RAII)
|
||||
|
||||
## **Description:**
|
||||
Resource Acquisition Is Initialization (RAII) is an idiom rather than a design pattern, but it's an important and widely used programming technique. RAII ties the lifetime of a resource (e.g., memory, files, locks) to the scope of an object. It ensures that the resource is automatically acquired when an object is created and automatically released when the object goes out of scope, thus preventing resource leaks and simplifying resource management.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Resource Management Class**: Create a resource management class (often referred to as a "wrapper" or "smart" class) that encapsulates the resource's allocation and deallocation logic.
|
||||
2. **Constructor**: In the constructor of the resource management class, acquire the resource (e.g., allocate memory, open a file, acquire a lock).
|
||||
3. **Destructor (or Dispose Method)**: In the destructor (or a dispose method for languages like C#), release the resource (e.g., deallocate memory, close a file, release a lock). The destructor is automatically called when the object goes out of scope.
|
||||
4. **Use in Client Code**: In your client code, create an instance of the resource management class. The resource will be automatically acquired when the object is created and automatically released when it goes out of scope.
|
||||
|
||||
## **Example:**
|
||||
A common example of RAII is managing dynamic memory in C++ using the `std::unique_ptr` smart pointer:
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
class MyResource {
|
||||
public:
|
||||
MyResource() {
|
||||
// Acquire a resource (e.g., allocate memory)
|
||||
data = new int[10];
|
||||
std::cout << "Resource acquired." << std::endl;
|
||||
}
|
||||
|
||||
~MyResource() {
|
||||
// Release the resource (e.g., deallocate memory)
|
||||
delete[] data;
|
||||
std::cout << "Resource released." << std::endl;
|
||||
}
|
||||
|
||||
void performOperation() {
|
||||
// Perform some operation with the resource
|
||||
std::cout << "Operation performed." << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
int* data;
|
||||
};
|
||||
|
||||
int main() {
|
||||
// Create an instance of MyResource
|
||||
MyResource resource;
|
||||
|
||||
// Use the resource
|
||||
resource.performOperation();
|
||||
|
||||
// Resource is automatically released when 'resource' goes out of scope
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
In this C++ example, the `MyResource` class acquires and releases a resource (dynamic memory) in its constructor and destructor, respectively. When you create an instance of `MyResource` in the `main` function, the resource is automatically acquired, and when `resource` goes out of scope at the end of `main`, the resource is automatically released. This ensures that you don't have to worry about explicitly managing the resource's lifecycle in your client code, reducing the risk of resource leaks.
|
|
@ -0,0 +1,71 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Singleton Pattern
|
||||
|
||||
## **Description:**
|
||||
The Singleton Pattern is a creational design pattern that ensures a class has only one instance and provides a global point of access to that instance. It is commonly used when you want to restrict the instantiation of a class to a single object and control access to that unique instance across the application.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Private Constructor**: Ensure that the class has a private constructor to prevent direct instantiation from external code.
|
||||
2. **Static Instance**: Create a static instance of the class within the class itself.
|
||||
3. **Lazy or Eager Initialization**: Decide whether to initialize the instance lazily (on-demand) or eagerly (at the time of class loading). Lazy initialization is preferred if resource usage should be minimized.
|
||||
4. **Static Method**: Provide a static method within the class to access the unique instance. This method should handle the creation of the instance if it doesn't exist or return the existing instance.
|
||||
5. **Thread Safety (Optional)**: If your application is multithreaded, ensure that the creation of the instance and access to it is thread-safe, especially if using lazy initialization.
|
||||
|
||||
## **Example:**
|
||||
A classic example of the Singleton Pattern is creating a configuration manager that provides access to application-wide configuration settings:
|
||||
|
||||
```java
|
||||
public class ConfigurationManager {
|
||||
private static ConfigurationManager instance; // Static instance variable
|
||||
private String configurationData;
|
||||
|
||||
// Private constructor to prevent external instantiation
|
||||
private ConfigurationManager() {
|
||||
// Initialize configurationData from a configuration file or other source
|
||||
configurationData = "Default configuration";
|
||||
}
|
||||
|
||||
// Static method to provide access to the unique instance
|
||||
public static ConfigurationManager getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new ConfigurationManager(); // Lazy initialization
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public String getConfigurationData() {
|
||||
return configurationData;
|
||||
}
|
||||
|
||||
public void setConfigurationData(String data) {
|
||||
configurationData = data;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this Java example:
|
||||
- The `ConfigurationManager` class has a private constructor to prevent external instantiation.
|
||||
- It contains a private static instance variable.
|
||||
- The `getInstance` static method is used to access the unique instance of the class. It initializes the instance lazily when called for the first time.
|
||||
- You can use `ConfigurationManager.getInstance()` to access the configuration manager from anywhere in your application.
|
||||
|
||||
```java
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
ConfigurationManager configManager1 = ConfigurationManager.getInstance();
|
||||
ConfigurationManager configManager2 = ConfigurationManager.getInstance();
|
||||
|
||||
// Both instances refer to the same unique object
|
||||
System.out.println(configManager1 == configManager2); // true
|
||||
|
||||
// Access and modify configuration data
|
||||
System.out.println(configManager1.getConfigurationData()); // Default configuration
|
||||
configManager1.setConfigurationData("New configuration");
|
||||
System.out.println(configManager2.getConfigurationData()); // New configuration
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The Singleton Pattern ensures that there's only one instance of `ConfigurationManager` throughout the application, providing a centralized and controlled way to manage configuration data.
|
Loading…
Add table
Add a link
Reference in a new issue