From 33a73031584f52e3fabb594ffbee1cf582f71a53 Mon Sep 17 00:00:00 2001
From: Joao Fraga <joao.fraga@feedzai.com>
Date: Mon, 30 Dec 2024 15:03:42 +0000
Subject: [PATCH] docs: dp.md

---
 content/post/dp.md | 457 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 457 insertions(+)
 create mode 100644 content/post/dp.md

diff --git a/content/post/dp.md b/content/post/dp.md
new file mode 100644
index 0000000..679218b
--- /dev/null
+++ b/content/post/dp.md
@@ -0,0 +1,457 @@
+---
+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
+
+with an additional 3 bonus patterns which I personally consider useful as well:
+
+- Singleton
+- Builder
+- Proxy
+
+# 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 ButtonAbstractFactory {
+    Button createButton();
+}
+
+public class WindowsButtonFactory implements ButtonAbstractFactory {
+    public Button createButton() {
+        return new WindowsButton();
+    }
+}
+
+public class MacButtonFactory implements ButtonAbstractFactory {
+    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 ButtonFactory {
+    public void display() {
+        Button button = createButton();
+        button.render();
+    }
+
+    protected abstract Button createButton();
+}
+
+public class WindowsButtonFactory extends ButtonFactory {
+    @Override
+    protected Button createButton() {
+        return new WindowsButton();
+    }
+}
+
+public class MacButtonFactory extends ButtonFactory {
+    @Override
+    protected Button createButton() {
+        return new MacButton();
+    }
+}
+```
+
+**Singleton**
+
+Ensures a class has only one instance and provides a global access point to it.
+This is often used for managing shared resources like configuration settings or database connections.
+
+```java
+public class Singleton {
+    private static Singleton instance;
+
+    private Singleton() {
+        // Private constructor to prevent instantiation
+    }
+
+    public static Singleton getInstance() {
+        if (instance == null) {
+            instance = new Singleton();
+        }
+        return instance;
+    }
+}
+```
+
+**Builder**
+
+Separates the construction of a complex object from its representation, allowing the same construction process to create different representations.
+This is often used to construct objects with many optional parameters.
+
+```java
+public class House {
+    private int rooms;
+    private boolean hasGarage;
+    private boolean hasGarden;
+
+    private House(Builder builder) {
+        this.rooms = builder.rooms;
+        this.hasGarage = builder.hasGarage;
+        this.hasGarden = builder.hasGarden;
+    }
+
+    public static class Builder {
+        private int rooms;
+        private boolean hasGarage;
+        private boolean hasGarden;
+
+        public Builder setRooms(int rooms) {
+            this.rooms = rooms;
+            return this;
+        }
+
+        public Builder setGarage(boolean hasGarage) {
+            this.hasGarage = hasGarage;
+            return this;
+        }
+
+        public Builder setGarden(boolean hasGarden) {
+            this.hasGarden = hasGarden;
+            return this;
+        }
+
+        public House build() {
+            return new House(this);
+        }
+    }
+}
+```
+
+# 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 list(String indent);
+}
+
+public class File implements FileSystemItem {
+    private String name;
+
+    public File(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public void list(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 list(String indent) {
+        System.out.println(indent + "Directory: " + name);
+        for (FileSystemItem item : items) {
+            item.list(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 source;
+
+    public EncryptionDecorator(DataSource source) {
+        this.source = source;
+    }
+
+    @Override
+    public void writeData(String data) {
+        source.writeData(encrypt(data));
+    }
+
+    @Override
+    public String readData() {
+        return decrypt(source.readData());
+    }
+
+    private String encrypt(String data) {
+        return "Encrypted[" + data + "]";
+    }
+
+    private String decrypt(String data) {
+        return data.replace("Encrypted[", "").replace("]", "");
+    }
+}
+```
+
+**Proxy**:
+
+Provides a placeholder or surrogate to control access to another object.
+This is commonly used for purposes like lazy initialization, access control, or logging.
+
+```java
+public interface Database {
+    void query(String sql);
+}
+
+public class RealDatabase implements Database {
+    public RealDatabase() {
+        connectToDatabase();
+    }
+
+    private void connectToDatabase() {
+        System.out.println("Connecting to the database...");
+    }
+
+    @Override
+    public void query(String sql) {
+        System.out.println("Executing query: " + sql);
+    }
+}
+
+public class DatabaseProxy implements Database {
+    private RealDatabase realDatabase;
+
+    @Override
+    public void query(String sql) {
+        if (realDatabase == null) {
+            realDatabase = new RealDatabase();
+        }
+        realDatabase.query(sql);
+    }
+}
+```
+
+# 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 BankTransferPayment implements PaymentStrategy {
+    @Override
+    public void pay(int amount) {
+        System.out.println("Paid " + amount + " using bank transfer.");
+    }
+}
+```
+
+**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!");
+    }
+}
+```