All About Design Patters
Satyendra Pandey
Posted on November 19, 2024
Design patterns in Java are reusable solutions to common software design problems. They help developers write more efficient, maintainable, and scalable code. Let's explore a few design patterns with simple examples.
1. Singleton Pattern
Purpose: Ensures that a class has only one instance and provides a global point of access to it.
Example: Database connection manager.
class DatabaseConnection {
private static DatabaseConnection instance;
private DatabaseConnection() {
// Private constructor to prevent instantiation
System.out.println("Database Connection Created!");
}
public static DatabaseConnection getInstance() {
if (instance == null) {
instance = new DatabaseConnection();
}
return instance;
}
}
public class SingletonExample {
public static void main(String[] args) {
DatabaseConnection db1 = DatabaseConnection.getInstance();
DatabaseConnection db2 = DatabaseConnection.getInstance();
System.out.println(db1 == db2); // Output: true
}
}
2. Factory Pattern
Purpose: Creates objects without exposing the instantiation logic to the client.
Example: Shape factory.
interface Shape {
void draw();
}
class Circle implements Shape {
public void draw() {
System.out.println("Drawing Circle");
}
}
class Square implements Shape {
public void draw() {
System.out.println("Drawing Square");
}
}
class ShapeFactory {
public static Shape getShape(String shapeType) {
if ("CIRCLE".equalsIgnoreCase(shapeType)) {
return new Circle();
} else if ("SQUARE".equalsIgnoreCase(shapeType)) {
return new Square();
}
return null;
}
}
public class FactoryExample {
public static void main(String[] args) {
Shape circle = ShapeFactory.getShape("CIRCLE");
circle.draw();
Shape square = ShapeFactory.getShape("SQUARE");
square.draw();
}
}
3. Observer Pattern
Purpose: Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified.
Example: Weather station.
import java.util.ArrayList;
import java.util.List;
// Observer interface
interface Observer {
void update(float temperature);
}
// Subject class
class WeatherStation {
private List<Observer> observers = new ArrayList<>();
private float temperature;
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void setTemperature(float temperature) {
this.temperature = temperature;
notifyObservers();
}
private void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature);
}
}
}
// Concrete Observer
class PhoneDisplay implements Observer {
@Override
public void update(float temperature) {
System.out.println("Phone Display: Temperature updated to " + temperature);
}
}
// Concrete Observer
class WebDisplay implements Observer {
@Override
public void update(float temperature) {
System.out.println("Web Display: Temperature updated to " + temperature);
}
}
public class ObserverExample {
public static void main(String[] args) {
WeatherStation station = new WeatherStation();
Observer phoneDisplay = new PhoneDisplay();
Observer webDisplay = new WebDisplay();
station.addObserver(phoneDisplay);
station.addObserver(webDisplay);
station.setTemperature(25.5f);
station.setTemperature(30.0f);
}
}
4. Strategy Pattern
Purpose: Defines a family of algorithms, encapsulates each one, and makes them interchangeable.
Example: Payment system.
interface PaymentStrategy {
void pay(int amount);
}
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " using Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " using PayPal");
}
}
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public ShoppingCart(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}
public class StrategyExample {
public static void main(String[] args) {
ShoppingCart cart1 = new ShoppingCart(new CreditCardPayment());
cart1.checkout(100);
ShoppingCart cart2 = new ShoppingCart(new PayPalPayment());
cart2.checkout(200);
}
}
5. Decorator Pattern
Purpose: Dynamically adds new behavior to an object.
Example: Adding features to a coffee order.
interface Coffee {
String getDescription();
double getCost();
}
class BasicCoffee implements Coffee {
public String getDescription() {
return "Basic Coffee";
}
public double getCost() {
return 5.0;
}
}
class MilkDecorator implements Coffee {
private Coffee coffee;
public MilkDecorator(Coffee coffee) {
this.coffee = coffee;
}
public String getDescription() {
return coffee.getDescription() + ", Milk";
}
public double getCost() {
return coffee.getCost() + 1.0;
}
}
class SugarDecorator implements Coffee {
private Coffee coffee;
public SugarDecorator(Coffee coffee) {
this.coffee = coffee;
}
public String getDescription() {
return coffee.getDescription() + ", Sugar";
}
public double getCost() {
return coffee.getCost() + 0.5;
}
}
public class DecoratorExample {
public static void main(String[] args) {
Coffee coffee = new BasicCoffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
System.out.println(coffee.getDescription() + ": $" + coffee.getCost());
}
}
Posted on November 19, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 27, 2024