


Design patterns are proven solutions to common problems in software design. They help in making the code more flexible, reusable, and easier to understand. In this blog post, we will explore some of the most commonly used design patterns in Java and provide examples of how to implement them.
Design patterns provide a standard terminology and are a guide to solving recurring design issues in software development. They help improve code readability and make it easier to manage.
Design patterns can be categorized into three main types:
These patterns deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. Examples include:
These patterns deal with object composition, ensuring that if one part of a system changes, the entire system doesn’t need to change. Examples include:
These patterns deal with object collaboration and delegation, focusing on communication between objects. Examples include:
Let’s dive deeper into some specific design patterns and see how to implement them in Java.
The Singleton pattern ensures that a class has only one instance and provides a global point of access to it.
Implementation:
java code
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Usage:
java
Copy code
public class Main {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
System.out.println(singleton);
}
}
The Factory pattern provides an interface for creating objects but allows subclasses to alter the type of objects that will be created.
Implementation:
Java code
interface Shape {
void draw();
}
class Circle implements Shape {
public void draw() {
System.out.println(“Drawing a Circle”);
}
}
class Square implements Shape {
public void draw() {
System.out.println(“Drawing a Square”);
}
}
class ShapeFactory {
public Shape getShape(String shapeType) {
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase(“CIRCLE”)) {
return new Circle();
} else if (shapeType.equalsIgnoreCase(“SQUARE”)) {
return new Square();
}
return null;
}
}
Usage:
java code
public class Main {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
Shape shape1 = shapeFactory.getShape(“CIRCLE”);
shape1.draw();
Shape shape2 = shapeFactory.getShape(“SQUARE”);
shape2.draw();
}
}
The Observer pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified.
Implementation:
java code
import java.util.ArrayList;import java.util.List;
interface Observer {
void update(String message);
}
class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + ” received message: “ + message);
}
}
class Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
Usage:
java code
public class Main {
public static void main(String[] args) {
Subject subject = new Subject();
Observer observer1 = new ConcreteObserver(“Observer 1”);
Observer observer2 = new ConcreteObserver(“Observer 2”);
subject.attach(observer1);
subject.attach(observer2);
subject.notifyObservers(“Hello Observers!”);
}
}
The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable.
Implementation:
java code
interface Strategy {
int doOperation(int num1, int num2);
}
class Addition implements Strategy {
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
class Subtraction implements Strategy {
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2) {
return strategy.doOperation(num1, num2);
}
}
Usage:
java code
public class Main {
public static void main(String[] args) {
Context context = new Context(new Addition());
System.out.println(“10 + 5 = “ + context.executeStrategy(10, 5));
context = new Context(new Subtraction());
System.out.println(“10 – 5 = “ + context.executeStrategy(10, 5));
}
}
Design patterns are essential tools for developers to solve common problems in software design efficiently. By understanding and implementing these patterns, you can enhance your coding skills and create better software.
To test your understanding of design patterns, take this short quiz!
What is a Singleton pattern used for?
Which pattern is used to notify multiple objects about state changes?
What does the Factory pattern provide?
By implementing design patterns in your Java projects, you can improve code quality, maintainability, and overall project success. Feel free to share your thoughts and experiences with design patterns in the comments below!
Comments are closed