init
This commit is contained in:
commit
c5cd492449
475 changed files with 27928 additions and 0 deletions
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Adapter Pattern
|
||||
|
||||
## **Description:**
|
||||
The Adapter Pattern is a structural design pattern that allows objects with incompatible interfaces to work together. It acts as a bridge between two incompatible interfaces, enabling them to collaborate without altering their source code. The Adapter Pattern is useful when you want to reuse existing classes or integrate third-party libraries that don't quite fit your desired interface.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Identify Interfaces**: Identify the two interfaces that need to work together but are incompatible.
|
||||
2. **Adapter Class**: Create an adapter class that implements the interface expected by the client code (the target interface) while containing an instance of the class with the incompatible interface (the adaptee).
|
||||
3. **Adapter Methods**: Within the adapter class, implement methods that map the methods of the target interface to the corresponding methods of the adaptee interface.
|
||||
4. **Client Code**: In the client code, use the adapter class to interact with the adaptee class as if it implements the target interface.
|
||||
|
||||
## **Example:**
|
||||
Suppose you have a legacy class `OldSystem` with an interface that is incompatible with your modern system, but you need to integrate the legacy functionality. Here's how the Adapter Pattern can be applied:
|
||||
|
||||
- **Incompatible Legacy Class (Adaptee)**: Define the `OldSystem` class with its existing interface.
|
||||
```java
|
||||
public class OldSystem {
|
||||
public void doOldStuff() {
|
||||
System.out.println("Doing old stuff in the legacy system.");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Target Interface**: Define the `NewSystem` interface that your modern system expects.
|
||||
```java
|
||||
public interface NewSystem {
|
||||
void doNewStuff();
|
||||
}
|
||||
```
|
||||
|
||||
- **Adapter Class**: Create an adapter class `Adapter` that implements the `NewSystem` interface and contains an instance of the `OldSystem` class.
|
||||
```java
|
||||
public class Adapter implements NewSystem {
|
||||
private OldSystem oldSystem;
|
||||
|
||||
public Adapter(OldSystem oldSystem) {
|
||||
this.oldSystem = oldSystem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doNewStuff() {
|
||||
// Delegate the new system's request to the old system's method
|
||||
oldSystem.doOldStuff();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Client Code**: In your modern system, use the `Adapter` class to work with the `OldSystem` as if it were a `NewSystem`.
|
||||
```java
|
||||
public class Client {
|
||||
public static void main(String[] args) {
|
||||
OldSystem legacySystem = new OldSystem();
|
||||
NewSystem adapter = new Adapter(legacySystem);
|
||||
|
||||
// Use the adapter to perform new system operations
|
||||
adapter.doNewStuff();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
By using the Adapter Pattern, you can integrate the legacy `OldSystem` class seamlessly into your modern system without changing the code of the legacy class. The adapter serves as a bridge, translating calls from the new system's interface to the old system's interface, allowing them to work together.
|
107
technology/programming/patterns/structural/Bridge Patterns.md
Normal file
107
technology/programming/patterns/structural/Bridge Patterns.md
Normal file
|
@ -0,0 +1,107 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Bridge Pattern
|
||||
|
||||
## **Description:**
|
||||
The Bridge Pattern is a structural design pattern that separates an object's abstraction (high-level logic) from its implementation (low-level details). It allows you to vary both the abstraction and the implementation independently, making it easier to extend and maintain complex systems. This pattern is particularly useful when you have a hierarchy of classes with multiple dimensions of variation.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Identify Abstraction and Implementation**: Identify the components of your system that have multiple dimensions of variation. This typically involves defining an abstraction (high-level logic) and one or more implementations (low-level details).
|
||||
2. **Abstraction Class**: Create an abstraction class that contains a reference to an implementation object. The abstraction class defines high-level methods and delegates the implementation details to the implementation object.
|
||||
3. **Implementation Interface or Abstract Class**: Define an interface or an abstract class for the implementation, which will be implemented by concrete implementation classes.
|
||||
4. **Concrete Implementation Classes**: Create concrete implementation classes that implement the interface or extend the abstract class defined for the implementation. These classes contain the low-level implementation details.
|
||||
5. **Client Code**: In your client code, use the abstraction class to interact with the high-level logic while providing or selecting the specific implementation at runtime.
|
||||
|
||||
## **Example:**
|
||||
Consider a drawing application where you have different shapes (e.g., circles, rectangles) that can be drawn using different rendering techniques (e.g., vector graphics, raster graphics). Here's how the Bridge Pattern can be applied:
|
||||
|
||||
- **Abstraction Class**: Create an abstraction class `Shape` that contains a reference to an implementation object `Renderer`.
|
||||
```java
|
||||
public abstract class Shape {
|
||||
protected Renderer renderer;
|
||||
|
||||
public Shape(Renderer renderer) {
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
public abstract void draw();
|
||||
}
|
||||
```
|
||||
|
||||
- **Implementation Interface**: Define an interface `Renderer` for the rendering implementation.
|
||||
```java
|
||||
public interface Renderer {
|
||||
void render();
|
||||
}
|
||||
```
|
||||
|
||||
- **Concrete Implementation Classes**: Create concrete implementation classes for different rendering techniques, such as `VectorRenderer` and `RasterRenderer`.
|
||||
```java
|
||||
public class VectorRenderer implements Renderer {
|
||||
@Override
|
||||
public void render() {
|
||||
System.out.println("Rendering as vector graphics.");
|
||||
}
|
||||
}
|
||||
|
||||
public class RasterRenderer implements Renderer {
|
||||
@Override
|
||||
public void render() {
|
||||
System.out.println("Rendering as raster graphics.");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Concrete Abstraction Classes**: Create concrete abstraction classes for different shapes, such as `Circle` and `Rectangle`, that extend the `Shape` class and provide specific implementations for the `draw` method.
|
||||
```java
|
||||
public class Circle extends Shape {
|
||||
private int radius;
|
||||
|
||||
public Circle(Renderer renderer, int radius) {
|
||||
super(renderer);
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw() {
|
||||
System.out.println("Drawing a circle with radius " + radius);
|
||||
renderer.render();
|
||||
}
|
||||
}
|
||||
|
||||
public class Rectangle extends Shape {
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
public Rectangle(Renderer renderer, int width, int height) {
|
||||
super(renderer);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw() {
|
||||
System.out.println("Drawing a rectangle with width " + width + " and height " + height);
|
||||
renderer.render();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Client Code**: In your application, use the abstraction classes to create shapes and specify the rendering technique at runtime.
|
||||
```java
|
||||
public class Client {
|
||||
public static void main(String[] args) {
|
||||
Renderer vectorRenderer = new VectorRenderer();
|
||||
Renderer rasterRenderer = new RasterRenderer();
|
||||
|
||||
Shape circle = new Circle(vectorRenderer, 5);
|
||||
Shape rectangle = new Rectangle(rasterRenderer, 10, 20);
|
||||
|
||||
circle.draw();
|
||||
rectangle.draw();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
By using the Bridge Pattern, you can vary the shapes and rendering techniques independently, making it easier to add new shapes or rendering methods without affecting existing code. This pattern promotes flexibility and maintainability in complex systems with multiple dimensions of variation.
|
|
@ -0,0 +1,93 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Composite Pattern
|
||||
|
||||
## **Description:**
|
||||
The Composite Pattern is a structural design pattern that allows you to compose objects into tree structures to represent part-whole hierarchies. It lets clients treat individual objects and compositions of objects uniformly. In other words, you can use the same interface to work with both single objects and compositions of objects. This pattern is particularly useful when dealing with hierarchical structures and you want to apply operations recursively.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Component Interface**: Define an abstract class or interface, often called `Component`, that represents the common interface for both leaf and composite objects. This interface includes methods that are common to all objects in the hierarchy.
|
||||
2. **Leaf Class**: Create a leaf class that implements the `Component` interface. Leaf objects are the individual objects that do not have children in the hierarchy.
|
||||
3. **Composite Class**: Create a composite class that also implements the `Component` interface. Composite objects can contain child components, including both leaf and other composite objects.
|
||||
4. **Add and Remove Methods**: In the composite class, provide methods to add and remove child components. These methods allow you to build and modify the hierarchical structure dynamically.
|
||||
5. **Client Code**: In your client code, work with objects through the `Component` interface. You can treat individual objects and compositions of objects uniformly, as they share a common interface.
|
||||
|
||||
## **Example:**
|
||||
Imagine you are building a graphical user interface (GUI) library that needs to handle a hierarchy of UI elements, including individual controls (buttons, text fields) and composite elements (e.g., windows containing other controls). Here's how the Composite Pattern can be applied:
|
||||
|
||||
- **Component Interface**: Define an abstract `UIComponent` interface that represents the common interface for all UI element
|
||||
```java
|
||||
public interface UIComponent {
|
||||
void render();
|
||||
}
|
||||
```
|
||||
|
||||
- **Leaf Class**: Create leaf classes like `Button` and `TextField` that implement the `UIComponent` interface.
|
||||
```java
|
||||
public class Button implements UIComponent {
|
||||
private String label;
|
||||
|
||||
public Button(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
System.out.println("Rendered Button: " + label);
|
||||
}
|
||||
}
|
||||
|
||||
public class TextField implements UIComponent {
|
||||
@Override
|
||||
public void render() {
|
||||
System.out.println("Rendered TextField");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Composite Class**: Create a composite class, such as `Window`, that implements the `UIComponent` interface and can contain child components.
|
||||
```java
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Window implements UIComponent {
|
||||
private List<UIComponent> children = new ArrayList<>();
|
||||
|
||||
public void add(UIComponent component) {
|
||||
children.add(component);
|
||||
}
|
||||
|
||||
public void remove(UIComponent component) {
|
||||
children.remove(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
System.out.println("Rendered Window");
|
||||
for (UIComponent child : children) {
|
||||
child.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Client Code**: In your GUI library or application, create instances of leaf objects and composite objects and use them through the `UIComponent` interface.
|
||||
```java
|
||||
public class Client {
|
||||
public static void main(String[] args) {
|
||||
UIComponent button1 = new Button("OK");
|
||||
UIComponent button2 = new Button("Cancel");
|
||||
UIComponent textField = new TextField();
|
||||
|
||||
Window window = new Window();
|
||||
window.add(button1);
|
||||
window.add(button2);
|
||||
window.add(textField);
|
||||
|
||||
window.render();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
By using the Composite Pattern, you can build complex UI hierarchies by composing individual UI elements (leaf objects) and containers (composite objects). Clients can work with these elements uniformly, regardless of whether they are individual controls or nested containers. This promotes code reusability and flexibility when dealing with hierarchical structures.
|
106
technology/programming/patterns/structural/Decorator Pattern.md
Normal file
106
technology/programming/patterns/structural/Decorator Pattern.md
Normal file
|
@ -0,0 +1,106 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Decorator Pattern
|
||||
|
||||
## **Description:**
|
||||
The Decorator Pattern is a structural design pattern that allows behavior to be added to individual objects, either statically or dynamically, without affecting the behavior of other objects from the same class. It is used to extend the functionality of classes in a flexible and reusable way, promoting the principle of open-closed design.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Component Interface**: Define an abstract class or interface, often called `Component`, that represents the base object's interface. This is the interface that decorators and concrete components will implement.
|
||||
2. **Concrete Component**: Create a concrete component class that implements the `Component` interface. This class represents the base object to which additional behavior can be added.
|
||||
3. **Decorator**: Create abstract decorator classes that also implement the `Component` interface. These classes have a reference to a `Component` object, and they can add, modify, or extend the behavior of the base component.
|
||||
4. **Concrete Decorators**: Create concrete decorator classes that extend the abstract decorator classes. These classes provide specific functionality that can be added to the base component.
|
||||
5. **Composition**: Use composition to combine the base component with one or more decorators. The decorators can be stacked, allowing multiple responsibilities to be added to the base component in a flexible manner.
|
||||
|
||||
## **Example:**
|
||||
Let's say you are building a text editor application, and you want to add text formatting features like bold, italic, and underline. You can use the Decorator Pattern to add these features dynamically to the text without changing the text object itself:
|
||||
|
||||
- **Component Interface**: Define an interface `Text` that represents the basic text functionality.
|
||||
```java
|
||||
public interface Text {
|
||||
String getContent();
|
||||
}
|
||||
```
|
||||
|
||||
- **Concrete Component**: Create a concrete component class `PlainText` that implements the `Text` interface.
|
||||
```java
|
||||
public class PlainText implements Text {
|
||||
private String content;
|
||||
|
||||
public PlainText(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Decorator**: Create an abstract decorator class `TextDecorator` that also implements the `Text` interface and has a reference to a `Text` object.
|
||||
```java
|
||||
public abstract class TextDecorator implements Text {
|
||||
protected Text decoratedText;
|
||||
|
||||
public TextDecorator(Text decoratedText) {
|
||||
this.decoratedText = decoratedText;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Concrete Decorators**: Create concrete decorator classes for formatting, such as `BoldText`, `ItalicText`, and `UnderlineText`, which extend `TextDecorator` and add specific formatting.
|
||||
```java
|
||||
public class BoldText extends TextDecorator {
|
||||
public BoldText(Text decoratedText) {
|
||||
super(decoratedText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContent() {
|
||||
return "<b>" + decoratedText.getContent() + "</b>";
|
||||
}
|
||||
}
|
||||
|
||||
public class ItalicText extends TextDecorator {
|
||||
public ItalicText(Text decoratedText) {
|
||||
super(decoratedText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContent() {
|
||||
return "<i>" + decoratedText.getContent() + "</i>";
|
||||
}
|
||||
}
|
||||
|
||||
public class UnderlineText extends TextDecorator {
|
||||
public UnderlineText(Text decoratedText) {
|
||||
super(decoratedText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContent() {
|
||||
return "<u>" + decoratedText.getContent() + "</u>";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Client Code**: In your text editor application, create an instance of the base `PlainText` class and decorate it with one or more formatting decorators.
|
||||
```java
|
||||
public class Client {
|
||||
public static void main(String[] args) {
|
||||
Text text = new PlainText("Hello, world!");
|
||||
|
||||
// Decorate the text with formatting
|
||||
text = new BoldText(text);
|
||||
text = new ItalicText(text);
|
||||
text = new UnderlineText(text);
|
||||
|
||||
// Output the formatted text
|
||||
System.out.println(text.getContent());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
By using the Decorator Pattern, you can add text formatting features to the base `PlainText` object dynamically. You can easily stack and combine different formatting decorators to achieve various formatting options without modifying the base text object's code. This pattern promotes flexibility and maintainability when extending the functionality of objects.
|
66
technology/programming/patterns/structural/Facade Pattern.md
Normal file
66
technology/programming/patterns/structural/Facade Pattern.md
Normal file
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Facade Pattern
|
||||
|
||||
## **Description:**
|
||||
The Facade Pattern is a structural design pattern that provides a simplified and unified interface to a set of interfaces in a subsystem. It acts as a front-facing interface to a complex system, making it easier for clients to interact with that system. The Facade Pattern promotes loose coupling and encapsulation by hiding the complexities of the subsystem behind a simple interface.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Subsystem**: Identify a complex subsystem or set of related classes that perform various tasks but have a complex and possibly fragmented interface.
|
||||
2. **Facade Class**: Create a facade class that encapsulates the subsystem's functionality and provides a simplified, high-level interface for clients.
|
||||
3. **Facade Methods**: Define methods in the facade class that correspond to the common operations or workflows that clients need to perform within the subsystem.
|
||||
4. **Client Code**: Clients interact with the subsystem through the facade class by calling its methods. Clients are shielded from the complexities of the subsystem.
|
||||
|
||||
## **Example:**
|
||||
Imagine you are developing a multimedia processing library with various components for image processing, audio processing, and video processing. Each component has its own set of classes and interfaces, and interacting with them individually can be complex. You can use the Facade Pattern to create a simplified interface for clients:
|
||||
|
||||
- **Subsystem Classes**: Define classes for image processing, audio processing, and video processing, each with its own set of methods and complexities.
|
||||
- **Facade Class**: Create a `MultimediaProcessor` facade class that provides high-level methods for common multimedia operations, such as `processImage`, `processAudio`, and `processVideo`.
|
||||
```java
|
||||
public class MultimediaProcessor {
|
||||
private ImageProcessor imageProcessor;
|
||||
private AudioProcessor audioProcessor;
|
||||
private VideoProcessor videoProcessor;
|
||||
|
||||
public MultimediaProcessor() {
|
||||
this.imageProcessor = new ImageProcessor();
|
||||
this.audioProcessor = new AudioProcessor();
|
||||
this.videoProcessor = new VideoProcessor();
|
||||
}
|
||||
|
||||
public void processImage(String imagePath) {
|
||||
imageProcessor.loadImage(imagePath);
|
||||
imageProcessor.applyFilters();
|
||||
imageProcessor.saveImage();
|
||||
}
|
||||
|
||||
public void processAudio(String audioPath) {
|
||||
audioProcessor.loadAudio(audioPath);
|
||||
audioProcessor.adjustVolume();
|
||||
audioProcessor.saveAudio();
|
||||
}
|
||||
|
||||
public void processVideo(String videoPath) {
|
||||
videoProcessor.loadVideo(videoPath);
|
||||
videoProcessor.extractAudio();
|
||||
videoProcessor.convertToFormat();
|
||||
videoProcessor.saveVideo();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Client Code**: In your client code, use the `MultimediaProcessor` facade class to perform multimedia operations without needing to interact with the individual image, audio, and video processing components directly.
|
||||
```java
|
||||
public class Client {
|
||||
public static void main(String[] args) {
|
||||
MultimediaProcessor multimediaProcessor = new MultimediaProcessor();
|
||||
|
||||
multimediaProcessor.processImage("sample.jpg");
|
||||
multimediaProcessor.processAudio("sample.mp3");
|
||||
multimediaProcessor.processVideo("sample.mp4");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
By using the Facade Pattern, you provide a simplified and unified interface (`MultimediaProcessor`) for clients to perform multimedia processing operations. Clients don't need to be aware of the individual complexities and intricacies of the subsystem components (image processing, audio processing, video processing), promoting code modularity and ease of use. The Facade Pattern is particularly valuable when dealing with complex systems or libraries with numerous components.
|
|
@ -0,0 +1,84 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
## Flyweight Pattern
|
||||
|
||||
## **Description:**
|
||||
The Flyweight Pattern is a structural design pattern that is used to minimize memory usage or computational expenses by sharing as much as possible with related objects. It is particularly useful when you need to create a large number of similar objects efficiently and the objects have common, intrinsic (shared) properties and extrinsic (unique) properties that can be separated.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Identify Shared and Non-Shared Parts**: Identify the parts of objects that can be shared among multiple instances (intrinsic state) and the parts that must remain unique to each instance (extrinsic state).
|
||||
2. **Flyweight Factory**: Create a flyweight factory that manages a pool of shared flyweight objects. The factory is responsible for creating and maintaining the flyweight objects.
|
||||
3. **Flyweight Interface**: Define a flyweight interface that declares methods for accessing and manipulating the intrinsic state.
|
||||
4. **Concrete Flyweight Classes**: Create concrete flyweight classes that implement the flyweight interface and represent the shared intrinsic state.
|
||||
5. **Client Code**: In your client code, use the flyweight factory to obtain flyweight objects. For the extrinsic state (unique to each object), pass it as a parameter when requesting a flyweight object.
|
||||
|
||||
## **Example:**
|
||||
Consider a text editor where you want to efficiently represent and display a large number of characters. Most characters share common properties like font, size, and color, while their positions and content are unique. Here's how the Flyweight Pattern can be applied:
|
||||
|
||||
- **Flyweight Interface**: Define a `Character` interface that represents the common properties of characters.
|
||||
```java
|
||||
public interface Character {
|
||||
void display(int positionX, int positionY);
|
||||
}
|
||||
```
|
||||
|
||||
- **Concrete Flyweight Class**: Create a concrete flyweight class `SharedCharacter` that implements the `Character` interface and represents the shared intrinsic state (font, size, color).
|
||||
```java
|
||||
public class SharedCharacter implements Character {
|
||||
private char symbol;
|
||||
private Font font;
|
||||
private int size;
|
||||
private Color color;
|
||||
|
||||
public SharedCharacter(char symbol, Font font, int size, Color color) {
|
||||
this.symbol = symbol;
|
||||
this.font = font;
|
||||
this.size = size;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display(int positionX, int positionY) {
|
||||
System.out.println("Symbol: " + symbol +
|
||||
", Font: " + font.getName() +
|
||||
", Size: " + size +
|
||||
", Color: " + color +
|
||||
", Position: (" + positionX + ", " + positionY + ")");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Flyweight Factory**: Create a flyweight factory `CharacterFactory` that manages a pool of shared flyweight objects.
|
||||
```java
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CharacterFactory {
|
||||
private Map<Character, Character> characterPool = new HashMap<>();
|
||||
|
||||
public Character getCharacter(char symbol, Font font, int size, Color color) {
|
||||
Character sharedCharacter = new SharedCharacter(symbol, font, size, color);
|
||||
characterPool.put(symbol, sharedCharacter);
|
||||
return sharedCharacter;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Client Code**: In your client code, use the `CharacterFactory` to obtain flyweight objects and pass the unique extrinsic state (position) as a parameter when displaying characters.
|
||||
```java
|
||||
public class Client {
|
||||
public static void main(String[] args) {
|
||||
CharacterFactory characterFactory = new CharacterFactory();
|
||||
|
||||
// Display characters at different positions with shared properties
|
||||
Character charA = characterFactory.getCharacter('A', Font.BOLD, 12, Color.BLACK);
|
||||
charA.display(10, 20);
|
||||
|
||||
Character charB = characterFactory.getCharacter('B', Font.ITALIC, 14, Color.RED);
|
||||
charB.display(30, 40);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
By using the Flyweight Pattern, you efficiently represent a large number of characters while sharing common properties, thus reducing memory usage. The extrinsic state (position) remains unique to each character instance, and the pattern helps manage shared and non-shared aspects effectively. This pattern is especially valuable in scenarios where many objects have a significant amount of shared state.
|
83
technology/programming/patterns/structural/Proxy Pattern.md
Normal file
83
technology/programming/patterns/structural/Proxy Pattern.md
Normal file
|
@ -0,0 +1,83 @@
|
|||
---
|
||||
obj: concept
|
||||
---
|
||||
# Proxy Pattern
|
||||
|
||||
## **Description:**
|
||||
The Proxy Pattern is a structural design pattern that provides a surrogate or placeholder for another object to control access to it. It allows you to create a level of indirection to an object, which can be useful for various purposes such as controlling access, lazy loading, logging, monitoring, or adding a security layer to the real object.
|
||||
|
||||
**How it's Used:**
|
||||
1. **Real Subject**: Define an interface that both the real subject and the proxy implement. This interface represents the common operations that the real subject and proxy can perform.
|
||||
2. **Proxy Class**: Create a proxy class that implements the same interface as the real subject. This proxy class contains a reference to the real subject.
|
||||
3. **Proxy Methods**: In the proxy methods, you can add additional behavior before or after delegating the request to the real subject. This additional behavior can include access control, logging, or lazy loading.
|
||||
4. **Client Code**: Clients interact with the proxy object, thinking it's the real subject. The proxy object handles the interaction with the real subject.
|
||||
|
||||
## **Example:**
|
||||
Consider a scenario where you have a large collection of images, and you want to load and display them only when needed to improve performance. You can use the Proxy Pattern to implement lazy loading:
|
||||
|
||||
- **Subject Interface**: Define an interface `Image` that represents the common operations for images.
|
||||
```java
|
||||
public interface Image {
|
||||
void display();
|
||||
}
|
||||
```
|
||||
|
||||
- **Real Subject**: Create a real subject class `RealImage` that implements the `Image` interface. This class represents the actual image and loads it when required.
|
||||
```java
|
||||
public class RealImage implements Image {
|
||||
private String filename;
|
||||
|
||||
public RealImage(String filename) {
|
||||
this.filename = filename;
|
||||
loadFromDisk();
|
||||
}
|
||||
|
||||
private void loadFromDisk() {
|
||||
System.out.println("Loading image: " + filename);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display() {
|
||||
System.out.println("Displaying image: " + filename);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Proxy Class**: Create a proxy class `ProxyImage` that also implements the `Image` interface. This class contains a reference to the real image but loads it lazily when requested.
|
||||
```java
|
||||
public class ProxyImage implements Image {
|
||||
private RealImage realImage;
|
||||
private String filename;
|
||||
|
||||
public ProxyImage(String filename) {
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display() {
|
||||
if (realImage == null) {
|
||||
realImage = new RealImage(filename);
|
||||
}
|
||||
realImage.display();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Client Code**: In your client code, use the `ProxyImage` class to interact with images. Images are loaded and displayed only when the `display` method is called.
|
||||
```java
|
||||
public class Client {
|
||||
public static void main(String[] args) {
|
||||
Image image1 = new ProxyImage("image1.jpg");
|
||||
Image image2 = new ProxyImage("image2.jpg");
|
||||
|
||||
// Images are loaded and displayed when requested
|
||||
image1.display();
|
||||
image2.display();
|
||||
|
||||
// No additional loading for the already displayed image
|
||||
image1.display();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
By using the Proxy Pattern, you can improve the performance of your application by loading and displaying images lazily. The proxy object (`ProxyImage`) handles the loading and displaying of the real images (`RealImage`) as needed. This pattern is also useful for scenarios where you need to control access to sensitive resources, log actions, or add additional functionality to an object without changing its core behavior.
|
Loading…
Add table
Add a link
Reference in a new issue