Welcome to this 3-part guide. In this post, I'll provide a basic introduction to design patterns, along with examples.
This specific post will cover what design patterns are, why we should know about them, the types of design patterns, and behavioral patterns.
Quick links:
What are Design Patterns?
Design patterns are proven solutions to common problems in software development. They help developers solve complex tasks in a structured way and allow them to reuse successful solutions, making their code easier to understand and maintain. Think of design patterns as blueprints for solving typical problems that occur when building software.
Why Should We Know About Them?
Knowing about design patterns helps developers solve common problems in a structured and efficient way, making code more reusable, maintainable, and scalable.
Think of a restaurant kitchen. The chef follows a recipe (design pattern) to prepare a dish. Instead of reinventing the process each time, the chef uses proven steps to consistently deliver the same quality dish. Similarly, design patterns help developers efficiently solve problems without reinventing solutions each time.
Types of Design Patterns:
In Java, design patterns are categorized into three main groups:
1. Creational Patterns: These patterns help with creating objects in a flexible and reusable way.
2. Structural Patterns: These patterns focus on how objects are arranged and connected to form larger systems.
3. Behavioral Patterns: These patterns deal with how objects interact and communicate with each other.
Behavioral Patterns
Behavioral patterns are concerned with how objects interact and communicate with each other.
Chain of Responsibility:
In an order processing system, you might have different levels of approval for orders (e.g., small orders go to a clerk, large orders go to a manager). The chain of responsibility pattern lets you pass the request along a chain of handlers until one handles it.
abstract class OrderHandler {
protected OrderHandler nextHandler;
public void setNextHandler(OrderHandler handler) {
this.nextHandler = handler;
}
public abstract void handleOrder(int amount);
}
class ClerkHandler extends OrderHandler {
public void handleOrder(int amount) {
if (amount < 500) {
System.out.println("Clerk handling order");
} else if (nextHandler != null) {
nextHandler.handleOrder(amount);
}
}
}
class ManagerHandler extends OrderHandler {
public void handleOrder(int amount) {
if (amount >= 500) {
System.out.println("Manager handling order");
} else if (nextHandler != null) {
nextHandler.handleOrder(amount);
}
}
}
Command:
In a text editor, the command pattern can be used to define actions like copy, paste, and undo, so that each action can be encapsulated as an object.
interface Command {
void execute();
}
class CopyCommand implements Command {
private TextEditor editor;
public CopyCommand(TextEditor editor) {
this.editor = editor;
}
public void execute() {
editor.copyText();
}
}
class TextEditor {
public void copyText() {
System.out.println("Text copied");
}
}
Observer:
In a weather monitoring system, multiple devices (e.g., mobile apps, weather stations) need to be updated whenever there is a change in the weather conditions.
interface Observer {
void update(String weather);
}
class WeatherStation {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void notifyObservers(String weather) {
for (Observer observer : observers) {
observer.update(weather);
}
}
}
class WeatherApp implements Observer {
public void update(String weather) {
System.out.println("Weather update: " + weather);
}
}
Strategy:
You can use different strategies for calculating shipping costs (e.g., regular shipping, expedited shipping). The strategy pattern allows you to switch between these strategies dynamically.
interface ShippingStrategy {
double calculateShippingCost(double weight);
}
class RegularShipping implements ShippingStrategy {
public double calculateShippingCost(double weight) {
return weight * 2;
}
}
class ExpeditedShipping implements ShippingStrategy {
public double calculateShippingCost(double weight) {
return weight * 5;
}
}
Template Method:
In a game, you might have different types of characters that follow a similar set of steps for attacking, but the specific details differ. The template method lets you define a general algorithm while allowing subclasses to override certain steps.
abstract class GameCharacter {
public void attack() {
moveToTarget();
performAttack();
celebrate();
}
protected void moveToTarget() {
System.out.println("Moving to target...");
}
protected abstract void performAttack();
protected void celebrate() {
System.out.println("Celebrating after attack...");
}
}
class Warrior extends GameCharacter {
protected void performAttack() {
System.out.println("Warrior performs sword attack!");
}
}
Top comments (0)