Last active
February 28, 2024 09:09
-
-
Save mazenmelouk/91477c0f1587625c013b88a116e7aae0 to your computer and use it in GitHub Desktop.
Simple Design Patterns Examples
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Map; | |
class Adapter { | |
private static final Map<String, MillimeterProductDimensions> PRODUCT_DIMENSIONS_IN_MILLIMETERS_STORE = Map.of( | |
"product1", new MillimeterProductDimensions(20, 10, 50) | |
); | |
static abstract class ProductDimensions { | |
private final double length; | |
private final double height; | |
private final double width; | |
private ProductDimensions(double length, double height, double width) { | |
this.length = length; | |
this.height = height; | |
this.width = width; | |
} | |
public double getLength() { | |
return length; | |
} | |
public double getHeight() { | |
return height; | |
} | |
public double getWidth() { | |
return width; | |
} | |
} | |
static class MillimeterProductDimensions extends ProductDimensions { | |
private MillimeterProductDimensions(double length, double height, double width) { | |
super(length, height, width); | |
} | |
} | |
static class InchProductDimensions extends ProductDimensions { | |
private InchProductDimensions(double length, double height, double width) { | |
super(length, height, width); | |
} | |
} | |
static class MillimeterToInchAdapter { | |
private final MillimeterProductDimensions millimeterProductDimensions; | |
public MillimeterToInchAdapter(MillimeterProductDimensions millimeterProductDimensions) { | |
this.millimeterProductDimensions = millimeterProductDimensions; | |
} | |
public InchProductDimensions convertToInches() { | |
// Convert millimeters to inches | |
return new InchProductDimensions( | |
millimeterProductDimensions.getLength() / 25.4, | |
millimeterProductDimensions.getWidth() / 25.4, | |
millimeterProductDimensions.getHeight() / 25.4 | |
); // 1 inch = 25.4 millimeters | |
} | |
} | |
public static void main(String[] args) { | |
MillimeterProductDimensions millimeter = PRODUCT_DIMENSIONS_IN_MILLIMETERS_STORE.get("product1"); | |
MillimeterToInchAdapter adapter = new MillimeterToInchAdapter(millimeter); | |
System.out.println("Length in inches: " + adapter.convertToInches()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Decorator { | |
// Component Interface | |
interface Order { | |
String getDescription(); | |
double getPrice(); | |
} | |
// Concrete Component | |
static class BaseOrder implements Order { | |
private final String description; | |
private final double price; | |
public BaseOrder(String description, double price) { | |
this.description = description; | |
this.price = price; | |
} | |
@Override | |
public String getDescription() { | |
return description; | |
} | |
@Override | |
public double getPrice() { | |
return price; | |
} | |
} | |
// Decorator | |
static abstract class OrderDecorator implements Order { | |
protected Order decoratedOrder; | |
public OrderDecorator(Order decoratedOrder) { | |
this.decoratedOrder = decoratedOrder; | |
} | |
@Override | |
public String getDescription() { | |
return decoratedOrder.getDescription(); | |
} | |
@Override | |
public double getPrice() { | |
return decoratedOrder.getPrice(); | |
} | |
} | |
// Concrete Decorators | |
static class PriorityOrder extends OrderDecorator { | |
public PriorityOrder(Order decoratedOrder) { | |
super(decoratedOrder); | |
} | |
@Override | |
public String getDescription() { | |
return decoratedOrder.getDescription() + ", Priority Order"; | |
} | |
@Override | |
public double getPrice() { | |
return decoratedOrder.getPrice() * 1.2; // Increase price for priority order | |
} | |
} | |
static class GiftWrap extends OrderDecorator { | |
public GiftWrap(Order decoratedOrder) { | |
super(decoratedOrder); | |
} | |
@Override | |
public String getDescription() { | |
return decoratedOrder.getDescription() + ", Gift Wrap"; | |
} | |
@Override | |
public double getPrice() { | |
return decoratedOrder.getPrice() + 5.0; // Additional cost for gift wrap | |
} | |
} | |
// Client | |
public static void main(String[] args) { | |
// Create a base order | |
Order order = new BaseOrder("Shirt", 20.0); | |
System.out.println("Order: " + order.getDescription() + ", Price: $" + order.getPrice()); | |
// Decorate with priority order | |
order = new PriorityOrder(order); | |
System.out.println("Order: " + order.getDescription() + ", Price: $" + order.getPrice()); | |
// Decorate with gift wrap | |
order = new GiftWrap(order); | |
System.out.println("Order: " + order.getDescription() + ", Price: $" + order.getPrice()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.Iterator; | |
// Radio Station class | |
class RadioStation { | |
private String frequency; | |
public RadioStation(String frequency) { | |
this.frequency = frequency; | |
} | |
public String getFrequency() { | |
return frequency; | |
} | |
} | |
// Iterator interface | |
interface StationIterator { | |
boolean hasNext(); | |
RadioStation next(); | |
} | |
// Concrete Iterator | |
class StationListIterator implements StationIterator { | |
private ArrayList<RadioStation> stations; | |
private int position = 0; | |
public StationListIterator(ArrayList<RadioStation> stations) { | |
this.stations = stations; | |
} | |
public boolean hasNext() { | |
return position < stations.size(); | |
} | |
public RadioStation next() { | |
if (hasNext()) { | |
return stations.get(position++); | |
} else { | |
return null; | |
} | |
} | |
} | |
// Aggregate interface | |
interface StationList { | |
StationIterator createIterator(); | |
} | |
// Concrete Aggregate | |
class RadioStationList implements StationList { | |
private ArrayList<RadioStation> stations; | |
public RadioStationList() { | |
stations = new ArrayList<>(); | |
} | |
public void addStation(RadioStation station) { | |
stations.add(station); | |
} | |
public StationIterator createIterator() { | |
return new StationListIterator(stations); | |
} | |
} | |
// Client code | |
public class RadioStationManager { | |
public static void main(String[] args) { | |
RadioStationList stationList = new RadioStationList(); | |
stationList.addStation(new RadioStation("95.5 FM")); | |
stationList.addStation(new RadioStation("101.1 FM")); | |
stationList.addStation(new RadioStation("104.3 FM")); | |
StationIterator iterator = stationList.createIterator(); | |
System.out.println("Radio Stations:"); | |
while (iterator.hasNext()) { | |
RadioStation station = iterator.next(); | |
System.out.println(station.getFrequency()); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.melouk.personal.observer; | |
import java.util.ArrayList; | |
import java.util.List; | |
public class ObserverPattern { | |
public enum OrderStatus{ | |
RECEIVED, | |
PACKING, | |
DELIVERING, | |
DELIVERED | |
} | |
public interface Observer { | |
void update(OrderStatus orderStatus); | |
} | |
public interface Subject { | |
void attach(Observer observer); | |
void detach(Observer observer); | |
void notifyObservers(); | |
} | |
public static class Order implements Subject {//concrete subject | |
private final List<Observer> observers = new ArrayList<>(); | |
private OrderStatus orderStatus; | |
public void setOrderStatus(OrderStatus orderStatus) { | |
this.orderStatus = orderStatus; | |
notifyObservers(); | |
} | |
@Override | |
public void attach(Observer observer) { | |
observers.add(observer); | |
} | |
@Override | |
public void detach(Observer observer) { | |
observers.remove(observer); | |
} | |
@Override | |
public void notifyObservers() { | |
for (Observer observer : observers) { | |
observer.update(orderStatus); | |
} | |
} | |
} | |
public static class Warehouse implements Observer { | |
@Override | |
public void update(OrderStatus orderStatus) { | |
//when it's received it should | |
System.out.println("Warehouse: Order status - " + orderStatus); | |
} | |
} | |
public static class Carrier implements Observer { | |
@Override | |
public void update(OrderStatus orderStatus) { | |
System.out.println("Carrier: Order status - " + orderStatus); | |
} | |
} | |
public static class Customer implements Observer { | |
@Override | |
public void update(OrderStatus orderStatus) { | |
// can send updates via email, mobile notification | |
System.out.println("Customer: Order status - " + orderStatus); | |
} | |
} | |
public static void main(String[] args) { | |
Order order = new Order(); | |
Observer restaurant = new Warehouse(); | |
Observer carrier = new Carrier(); | |
Observer customer = new Customer(); | |
order.attach(restaurant); | |
order.attach(carrier); | |
order.attach(customer); | |
// Signal the order is received | |
order.setOrderStatus(OrderStatus.RECEIVED); | |
// Ideally we could send the order id in the notification so that the warehouse can look it up | |
// and package it | |
order.setOrderStatus(OrderStatus.PACKING); | |
order.setOrderStatus(OrderStatus.DELIVERING); | |
order.setOrderStatus(OrderStatus.DELIVERED); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PaymentsFactory { | |
// Payment interface | |
public interface Payment { | |
void processPayment(); | |
} | |
// Concrete payment classes | |
public static class CreditCardPayment implements Payment { | |
@Override | |
public void processPayment() { | |
System.out.println("Processing credit card payment..."); | |
} | |
} | |
public static class PayPalPayment implements Payment { | |
@Override | |
public void processPayment() { | |
System.out.println("Processing PayPal payment..."); | |
} | |
} | |
enum PaymentMethod { | |
PAYPAL, | |
CREDIT_CARD | |
} | |
// Payment factory interface | |
public static class PaymentFactory { | |
Payment createPayment(PaymentMethod paymentMethod) { | |
return switch (paymentMethod) { | |
case PAYPAL -> new PayPalPayment(); | |
case CREDIT_CARD -> new CreditCardPayment(); | |
}; | |
} | |
} | |
// Client class | |
public static class PaymentClient { | |
private final PaymentFactory factory; | |
public PaymentClient(PaymentFactory factory) { | |
this.factory = factory; | |
} | |
public void makePayment(PaymentMethod paymentMethod) { | |
Payment payment = factory.createPayment(paymentMethod); | |
payment.processPayment(); | |
} | |
} | |
// Example usage | |
public class Main { | |
public void main(String[] args) { | |
// Create payment factories | |
PaymentClient paymentClient = new PaymentClient(new PaymentFactory()); | |
// Make payments using clients | |
paymentClient.makePayment(PaymentMethod.CREDIT_CARD); | |
paymentClient.makePayment(PaymentMethod.PAYPAL); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Date; | |
public class Person { | |
// Required attributes | |
private final String firstName; | |
private final String lastName; | |
// Optional attributes | |
private String middleName; | |
private String[] addresses; | |
private String nationality; | |
private String religion; | |
private Date dateOfBirth; | |
private String sex; | |
private String countryOfResidency; | |
private Person(Builder builder) { | |
this.firstName = builder.firstName; | |
this.middleName = builder.middleName; | |
this.lastName = builder.lastName; | |
this.addresses = builder.addresses; | |
this.nationality = builder.nationality; | |
this.religion = builder.religion; | |
this.dateOfBirth = builder.dateOfBirth; | |
this.sex = builder.sex; | |
this.countryOfResidency = builder.countryOfResidency; | |
} | |
// Getter methods for attributes | |
public static class Builder { | |
// Required attributes | |
private final String firstName; | |
private final String lastName; | |
// Optional attributes | |
private String middleName; | |
private String[] addresses; | |
private String nationality; | |
private String religion; | |
private Date dateOfBirth; | |
private String sex; | |
private String countryOfResidency; | |
// Constructor with required attributes | |
public Builder(String firstName, String lastName) { | |
this.firstName = firstName; | |
this.lastName = lastName; | |
} | |
// Setter methods for optional attributes | |
public Builder middleName(String middleName) { | |
this.middleName = middleName; | |
return this; | |
} | |
public Builder addresses(String[] addresses) { | |
this.addresses = addresses; | |
return this; | |
} | |
public Builder nationality(String nationality) { | |
this.nationality = nationality; | |
return this; | |
} | |
public Builder religion(String religion) { | |
this.religion = religion; | |
return this; | |
} | |
public Builder dateOfBirth(Date dateOfBirth) { | |
this.dateOfBirth = dateOfBirth; | |
return this; | |
} | |
public Builder sex(String sex) { | |
this.sex = sex; | |
return this; | |
} | |
public Builder countryOfResidency(String countryOfResidency) { | |
this.countryOfResidency = countryOfResidency; | |
return this; | |
} | |
// Build method to create Person object | |
public Person build() { | |
return new Person(this); | |
} | |
} | |
// Other methods and functionalities of the Person class | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.List; | |
import java.util.Map; | |
import java.util.Random; | |
import java.util.concurrent.ConcurrentHashMap; | |
class Proxy { | |
interface DataLoader { | |
List<Double> loadData(String key); | |
} | |
static class RemoteDataLoader implements DataLoader { | |
@Override | |
public List<Double> loadData(String key) { | |
//Assume it does a remote call | |
return List.of(new Random().nextDouble()); | |
} | |
} | |
static class CachingDataLoader implements DataLoader { | |
private final DataLoader remoteDataLoader; | |
private final Map<String, List<Double>> cache; | |
public CachingDataLoader(DataLoader remoteDataLoader) { | |
this.remoteDataLoader = remoteDataLoader; | |
this.cache = new ConcurrentHashMap<>(); | |
} | |
@Override | |
public List<Double> loadData(String key) { | |
return cache.computeIfAbsent(key, remoteDataLoader::loadData); | |
} | |
} | |
static class MetricsDataLoader implements DataLoader { | |
private final DataLoader remoteDataLoader; | |
MetricsDataLoader(DataLoader remoteDataLoader) { | |
this.remoteDataLoader = remoteDataLoader; | |
} | |
@Override | |
public List<Double> loadData(String key) { | |
long tick = System.nanoTime(); | |
List<Double> result = remoteDataLoader.loadData(key); | |
long toc = System.nanoTime(); | |
System.out.println("Time taken = " + (toc - tick) + " ns"); | |
return result; | |
} | |
} | |
public static void main(String[] args) { | |
DataLoader remoteDataLoader = new RemoteDataLoader(); | |
DataLoader cachingDataLoader = new CachingDataLoader(remoteDataLoader); | |
DataLoader metrics = new MetricsDataLoader(remoteDataLoader); | |
System.out.println(cachingDataLoader.loadData("a")); | |
System.out.println(cachingDataLoader.loadData("a")); | |
System.out.println(metrics.loadData("a")); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Singleton { | |
private static Singleton instance; | |
// Private constructor to prevent instantiation from outside | |
private Singleton() {} | |
// Static method to return the singleton instance | |
public static Singleton getInstance() { | |
if (instance == null) {// Check if the instance is not created. | |
instance = new Singleton(); | |
} | |
return instance; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class SingeltonEager { | |
// Here the instance is created upon class creation. | |
private static final SingeltonEager INSTANCE = new SingeltonEager(); | |
// Private constructor to prevent instantiation from outside | |
private SingeltonEager() {} | |
public static SingeltonEager getInstance() { | |
return INSTANCE; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class SingletonThreadsafe { | |
private static volatile SingletonThreadsafe instance; | |
// Private constructor to prevent instantiation from outside | |
private SingletonThreadsafe() {} | |
// Static method to return the singleton instance with double locking | |
public static SingletonThreadsafe getInstance() { | |
if (instance == null) { | |
synchronized (Singleton.class) { | |
if (instance == null) { | |
instance = new Singleton(); | |
} | |
} | |
} | |
return instance; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Interface defining the payment strategy | |
interface PaymentStrategy { | |
void pay(double amount); | |
} | |
// Concrete implementation for Credit Card payment | |
class CreditCardPayment implements PaymentStrategy { | |
private String cardNumber; | |
private String expiryDate; | |
private String cvv; | |
public CreditCardPayment(String cardNumber, String expiryDate, String cvv) { | |
this.cardNumber = cardNumber; | |
this.expiryDate = expiryDate; | |
this.cvv = cvv; | |
} | |
@Override | |
public void pay(double amount) { | |
System.out.println("Paid " + amount + " via Credit Card."); | |
// Additional logic specific to credit card payment | |
} | |
} | |
// Concrete implementation for PayPal payment | |
class PayPalPayment implements PaymentStrategy { | |
private String email; | |
private String password; | |
public PayPalPayment(String email, String password) { | |
this.email = email; | |
this.password = password; | |
} | |
@Override | |
public void pay(double amount) { | |
System.out.println("Paid " + amount + " via PayPal."); | |
// Additional logic specific to PayPal payment | |
} | |
} | |
// Context class that allows clients to use different payment strategies | |
class PaymentContext { | |
private PaymentStrategy paymentStrategy; | |
public PaymentContext(PaymentStrategy paymentStrategy) { | |
this.paymentStrategy = paymentStrategy; | |
} | |
public void setPaymentStrategy(PaymentStrategy paymentStrategy) { | |
this.paymentStrategy = paymentStrategy; | |
} | |
public void processPayment(double amount) { | |
paymentStrategy.pay(amount); | |
} | |
} | |
// Client code demonstrating the usage of different payment strategies | |
public class PaymentExample { | |
public static void main(String[] args) { | |
PaymentStrategy creditCardStrategy = new CreditCardPayment("1234 5678 9012 3456", "12/25", "123"); | |
PaymentStrategy paypalStrategy = new PayPalPayment("example@example.com", "password"); | |
PaymentContext paymentContext = new PaymentContext(creditCardStrategy); | |
paymentContext.processPayment(100.00); // Pay via Credit Card | |
paymentContext.setPaymentStrategy(paypalStrategy); | |
paymentContext.processPayment(50.00); // Pay via PayPal | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment