diff --git a/content/post/dp.md b/content/post/dp.md new file mode 100644 index 0000000..d5adea7 --- /dev/null +++ b/content/post/dp.md @@ -0,0 +1,347 @@ +--- +title: "DP - Design Patterns" +description: "Design Patterns in Java." +date: 2024-12-30T13:00:00Z +draft: false +--- + +Overview of the simplest and most common design patterns according to the book *"Design Patterns Elements of Reusable Object-Oriented Software"*: + +- Abstract Factory +- Factory Method +- Adapter +- Composite +- Decorator +- Observer +- Strategy +- Template Method + +# Creational Patterns + +**Abstract Factory**: + +Creates families of related objects without specifying their concrete classes. +It provides a higher level of abstraction, enabling the client to produce multiple types of objects from a single factory. + +```java +public interface ButtonFactory { + Button createButton(); +} + +public class WindowsButtonFactory implements ButtonFactory { + public Button createButton() { + return new WindowsButton(); + } +} + +public class MacButtonFactory implements ButtonFactory { + public Button createButton() { + return new MacButton(); + } +} + +public interface Button { + void render(); +} + +public class WindowsButton implements Button { + public void render() { + System.out.println("Rendering Windows Button"); + } +} + +public class MacButton implements Button { + public void render() { + System.out.println("Rendering Mac Button"); + } +} +``` + +**Factory Method**: + +Defines a method for creating objects, but allows subclasses to decide which object to instantiate. +This pattern promotes loose coupling by relying on the subclass for the specific implementation. + +```java +public interface Button { + void render(); +} + +public class WindowsButton implements Button { + public void render() { + System.out.println("Rendering Windows Button"); + } +} + +public class MacButton implements Button { + public void render() { + System.out.println("Rendering Mac Button"); + } +} + +public abstract class UIFactory { + public void renderInterface() { + Button button = createButton(); + button.render(); + } + + protected abstract Button createButton(); +} + +public class WindowsUIFactory extends UIFactory { + @Override + protected Button createButton() { + return new WindowsButton(); + } +} + +public class MacUIFactory extends UIFactory { + @Override + protected Button createButton() { + return new MacButton(); + } +} +``` + +# Structural Patterns + +**Adapter**: + +Acts as a bridge between two incompatible interfaces. +It allows existing classes to work together without modifying their source code by adapting their interfaces. + +```java +public interface USB { + void connectWithUSBPort(); +} + +public class HDMI { + public void connectWithHDMIPort() { + System.out.println("Connected using HDMI port"); + } +} + +public class HDMIToUSBAdapter implements USB { + private HDMI hdmiDevice; + + public HDMIToUSBAdapter(HDMI hdmiDevice) { + this.hdmiDevice = hdmiDevice; + } + + @Override + public void connectWithUSBPort() { + System.out.print("Adapting HDMI to USB: "); + hdmiDevice.connectWithHDMIPort(); + } +} +``` + +**Composite**: + +Enables you to compose objects into tree structures to represent part-whole hierarchies. +The pattern treats individual objects and compositions of objects uniformly, simplifying client code. + +```java +public interface FileSystemItem { + void display(String indent); +} + +public class File implements FileSystemItem { + private String name; + + public File(String name) { + this.name = name; + } + + @Override + public void display(String indent) { + System.out.println(indent + "File: " + name); + } +} + +public class Directory implements FileSystemItem { + private String name; + private List<FileSystemItem> items = new ArrayList<>(); + + public Directory(String name) { + this.name = name; + } + + public void add(FileSystemItem item) { + items.add(item); + } + + public void remove(FileSystemItem item) { + items.remove(item); + } + + @Override + public void display(String indent) { + System.out.println(indent + "Directory: " + name); + for (FileSystemItem item : items) { + item.display(indent + " "); + } + } +} +``` + +**Decorator**: + +Attaches additional behavior or responsibilities to an object dynamically. +It provides a flexible alternative to subclassing for extending functionality. + +```java +public interface DataSource { + void writeData(String data); + String readData(); +} + +public class FileDataSource implements DataSource { + private String filename; + + public FileDataSource(String filename) { + this.filename = filename; + } + + @Override + public void writeData(String data) { + System.out.println("Writing data to " + filename); + } + + @Override + public String readData() { + return "Reading data from " + filename; + } +} + +public class EncryptionDecorator implements DataSource { + private DataSource wrappee; + + public EncryptionDecorator(DataSource source) { + this.wrappee = source; + } + + @Override + public void writeData(String data) { + wrappee.writeData(encrypt(data)); + } + + @Override + public String readData() { + return decrypt(wrappee.readData()); + } + + private String encrypt(String data) { + return "Encrypted[" + data + "]"; + } + + private String decrypt(String data) { + return data.replace("Encrypted[", "").replace("]", ""); + } +} +``` + +# Behavioral Patterns + +**Observer**: + +Defines a one-to-many dependency between objects, where a change in the state of one object automatically notifies and updates all its dependents. +This pattern is particularly useful for implementing event-driven systems. + +```java +public interface Observer { + void update(String message); +} + +public class NewsSubscriber implements Observer { + private String name; + + public NewsSubscriber(String name) { + this.name = name; + } + + @Override + public void update(String message) { + System.out.println(name + " received update: " + message); + } +} + +public class NewsPublisher { + private List<Observer> observers = new ArrayList<>(); + + public void subscribe(Observer observer) { + observers.add(observer); + } + + public void unsubscribe(Observer observer) { + observers.remove(observer); + } + + public void notifyObservers(String message) { + for (Observer observer : observers) { + observer.update(message); + } + } +} +``` + +**Strategy**: + +Encapsulates interchangeable behaviors and algorithms, allowing you to select them at runtime. +This pattern promotes the Open/Closed Principle by enabling new strategies to be introduced without altering existing code. + +```java +public interface PaymentStrategy { + void pay(int amount); +} + +public class CreditCardPayment implements PaymentStrategy { + @Override + public void pay(int amount) { + System.out.println("Paid " + amount + " using credit card."); + } +} + +public class PayPalPayment implements PaymentStrategy { + @Override + public void pay(int amount) { + System.out.println("Paid " + amount + " using PayPal."); + } +} +``` + +**Template Method**: + +Defines the skeleton of an algorithm in a base class and allows subclasses to override specific steps of the algorithm without changing its structure. +This ensures code reuse while maintaining flexibility for customization. + +```java +public abstract class Game { + public final void play() { + initialize(); + startPlay(); + endPlay(); + } + + protected abstract void initialize(); + protected abstract void startPlay(); + protected abstract void endPlay(); +} + +public class Chess extends Game { + @Override + protected void initialize() { + System.out.println("Chess Game Initialized!"); + } + + @Override + protected void startPlay() { + System.out.println("Chess Game Started!"); + } + + @Override + protected void endPlay() { + System.out.println("Chess Game Finished!"); + } +} +```