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