Java design patterns
What is the design pattern?
In software engineering, a design pattern is a reusable solution to a common problem that can occur in software design. Design patterns provide a template or guide for creating code that solves a specific problem in a consistent and efficient manner.
In Java, design patterns are commonly used to help developers build robust, maintainable, and scalable applications. There are three types of design patterns: creational, structural, and behavioral.
Creational patterns deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. Structural patterns deal with object composition, where the goal is to simplify the way components of a system are put together. Behavioral patterns deal with communication between objects, and the goal is to increase flexibility and communication between components.
So today I introduce Some examples of design patterns in Java including Singleton, Factory Method, and Observer. By utilizing these design patterns, developers can create software that is more modular, easier to maintain and extend, and less prone to errors.
1. Singleton Pattern:
Singleton Design Pattern: The Singleton pattern ensures that a class has only one instance and provides a global point of access to it. It is commonly used in scenarios where there should be a single instance of a class that controls access to some shared resource or manages a global state.
Explanation: To implement the Singleton pattern, you need to make the class’s constructor private to prevent direct instantiation from other classes. The class itself provides a static method to access the single instance. Upon the first call to this method, the instance is created and cached. Subsequent calls return the cached instance.
Here’s an example of a Singleton class in Java:
public class Singleton {
private static Singleton instance;
private Singleton() {
// private constructor
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Conclusion:
The Singleton pattern provides a way to ensure that only one instance of a class exists at any given time. It allows global access to this instance, which can be useful for managing shared resources or maintaining a central state.
2. Factory Pattern:
The Factory Method pattern provides an interface for creating objects but allows subclasses to decide which class to instantiate. It encapsulates the object creation process and provides flexibility in object creation without tightly coupling the client code to the concrete classes.
Explanation:
The Factory Method pattern uses an abstract class or interface to define a method for creating objects. Subclasses implement this method to produce instances of specific classes based on the required logic. The client code interacts with the factory method through the abstract class or interface, without knowing the specific class being instantiated.
Here is an example:
public abstract class Vehicle {
public abstract void drive();
}
public class Car extends Vehicle {
@Override
public void drive() {
System.out.println("Driving a car...");
}
}
public class Bike extends Vehicle {
@Override
public void drive() {
System.out.println("Riding a bike...");
}
}
public interface VehicleFactory {
Vehicle createVehicle();
}
public class CarFactory implements VehicleFactory {
@Override
public Vehicle createVehicle() {
return new Car();
}
}
public class BikeFactory implements VehicleFactory {
@Override
public Vehicle createVehicle() {
return new Bike();
}
}
In the example, the Vehicle
abstract class defines the interface for the products, while Car
and Bike
are concrete implementations. The VehicleFactory
the interface declares the factory method createVehicle()
, which is implemented by CarFactory
and BikeFactory
to create instances of the corresponding products.
Conclusion: The Factory Method pattern allows for flexible object creation by delegating the responsibility of instantiation to subclasses. It promotes loose coupling between the client code and the concrete classes, making it easier to add new products without modifying existing code.
3. Observer Pattern:
The Observer pattern defines a one-to-many dependency between objects, so that when one object changes its state, all its dependents are notified and updated automatically. It facilitates loose coupling and promotes separation of concerns between the subject (observable) and the observers (subscribers).
Explanation:
In the Observer pattern, there are two main entities: the subject and the observers. The subject maintains a list of observers and provides methods to subscribe/unsubscribe them. Observers implement a common interface that defines the update method. When the subject’s state changes, it notifies all registered observers, and they update themselves accordingly.
Here’s an example of the Observer pattern in Java
import java.util.ArrayList;
import java.util.List;
public interface Observer {
void update();
}
public class Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
// Additional methods for manipulating the subject's state
}
public class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update() {
System.out.println(name + " received an update!");
}
}
In this example, the Subject
class represents the subject being observed, which maintains a list of observers. The Observer
interface defines the update method that observers implement. When the subject's state changes, it calls, which triggers the update method in each registered observer.
Conclusion:
The Observer pattern allows for a decoupled relationship between the subject and observers. It provides a mechanism for objects to be notified of changes in the state of other objects, facilitating loose coupling, modularity, and separation of concerns.
These design patterns in Java offer reusable solutions to common software design problems, enhancing code maintainability, flexibility, and reusability.
Keep reading
Subscribe to my newsletter
Read articles from Tushar kant directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Tushar kant
Tushar kant
Java || SpringBoot ||AWS