Skip to content

Commit

Permalink
docs: dp.md
Browse files Browse the repository at this point in the history
  • Loading branch information
Fraguinha committed Dec 30, 2024
1 parent fb7d41d commit 584e658
Showing 1 changed file with 347 additions and 0 deletions.
347 changes: 347 additions & 0 deletions content/post/dp.md
Original file line number Diff line number Diff line change
@@ -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!");
}
}
```

0 comments on commit 584e658

Please sign in to comment.