0% found this document useful (0 votes)
8 views7 pages

Detailed Design Patterns

This guide outlines 7 major design patterns in Java, including Singleton, Factory, Builder, Observer, Strategy, Decorator, and Adapter patterns. Each pattern is explained with its purpose, significance, and examples, emphasizing their role in creating reusable, maintainable, and scalable code. Understanding these patterns enhances software architecture and improves developer communication.

Uploaded by

Deepak Pal
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views7 pages

Detailed Design Patterns

This guide outlines 7 major design patterns in Java, including Singleton, Factory, Builder, Observer, Strategy, Decorator, and Adapter patterns. Each pattern is explained with its purpose, significance, and examples, emphasizing their role in creating reusable, maintainable, and scalable code. Understanding these patterns enhances software architecture and improves developer communication.

Uploaded by

Deepak Pal
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

Detailed Guide: 7 Major Design Patterns in Java

Design patterns represent best practices used by experienced object-oriented software developers. They
provide time-tested solutions to common design problems, promoting reusable, maintainable, and scalable
code. Understanding these patterns helps in building robust software architectures and improves
communication among developers.

This guide details 7 major design patterns in Java, outlining the purpose, significance, and including
explained examples.

1. Singleton Pattern

Purpose: Ensure a class has only one instance and provide a global point of access to it.

Significance: This pattern is essential when exactly one object is needed to coordinate actions across a
system. It is commonly used for managing shared resources such as configuration settings, logging, or
database connections.

Detailed Explanation: In the Singleton pattern, the constructor is declared private to prevent direct
instantiation. A static method (often named getInstance) is used to control the instantiation process, ensuring
that only one instance is ever created. This approach provides lazy initialization and controlled access to the
unique instance.
public class Singleton {
// Static variable to hold the one instance of the class
private static Singleton instance;

// Private constructor to prevent instantiation


private Singleton() {}

// Public method to provide access to the instance


public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}

// Example method
public void showMessage() {
System.out.println("Hello from Singleton!");
}
}

2. Factory Pattern

Purpose: Create objects without exposing the creation logic to the client and refer to newly created objects
using a common interface.
Detailed Guide: 7 Major Design Patterns in Java

Significance: The Factory pattern centralizes the creation of objects, making the code more flexible and
easier to maintain. It decouples the instantiation process from the client code, allowing the system to
introduce new products without modifying existing code.

Detailed Explanation: By using a Factory, the client code calls a single method to create objects, while the
Factory decides which subclass to instantiate based on input parameters.
interface Animal {
void sound();
}

class Dog implements Animal {


public void sound() {
System.out.println("Woof");
}
}

class Cat implements Animal {


public void sound() {
System.out.println("Meow");
}
}

class AnimalFactory {
public static Animal getAnimal(String type) {
if ("dog".equalsIgnoreCase(type))
return new Dog();
else if ("cat".equalsIgnoreCase(type))
return new Cat();
return null;
}
}

3. Builder Pattern

Purpose: Separate the construction of a complex object from its representation, enabling the same
construction process to create different representations.

Significance: The Builder pattern is useful for creating objects that require numerous parameters or complex
configurations. It helps avoid the telescoping constructor anti-pattern and improves code readability by
providing a clear and flexible way to construct objects.

Detailed Explanation: With the Builder pattern, a nested Builder class is used to assemble the object
step-by-step. The final build method aggregates all parameters to create the immutable object.
class Pizza {
private String base;
Detailed Guide: 7 Major Design Patterns in Java

private String cheese;


private String toppings;

// Private constructor
private Pizza() {}

// Static nested Builder class


public static class Builder {
private String base;
private String cheese;
private String toppings;

public Builder base(String base) {


this.base = base;
return this;
}

public Builder cheese(String cheese) {


this.cheese = cheese;
return this;
}

public Builder toppings(String toppings) {


this.toppings = toppings;
return this;
}

public Pizza build() {


Pizza pizza = new Pizza();
pizza.base = this.base;
pizza.cheese = this.cheese;
pizza.toppings = this.toppings;
return pizza;
}
}

// Method to display the pizza details


public void display() {
System.out.println(base + ", " + cheese + ", " + toppings);
}
}

4. Observer Pattern

Purpose: Define a one-to-many dependency between objects so that when one object (the subject) changes
state, all its dependents (observers) are notified.

Significance: This pattern is particularly useful in event-driven applications, such as GUIs, where changes in
one component need to be reflected in others. It promotes loose coupling between the subject and its
Detailed Guide: 7 Major Design Patterns in Java

observers.

Detailed Explanation: The Observer pattern relies on a subscription mechanism. Observers register
themselves with a subject, and when an event occurs, the subject sends notifications to all subscribed
observers. This decouples the subject from having to know the exact details of its observers.
import java.util.*;

interface Observer {
void update(String message);
}

class User implements Observer {


private String name;
public User(String name) { this.name = name; }

public void update(String message) {


System.out.println(name + " received: " + message);
}
}

class Channel {
private List<Observer> subscribers = new ArrayList<>();

public void subscribe(Observer o) {


subscribers.add(o);
}

public void notifyAllObservers(String msg) {


for (Observer o : subscribers) {
o.update(msg);
}
}
}

5. Strategy Pattern

Purpose: Define a family of algorithms, encapsulate each one, and make them interchangeable. The strategy
pattern allows the algorithm to vary independently from clients that use it.

Significance: This pattern promotes the Open/Closed principle by enabling new algorithms to be added
without altering existing code. It also helps in isolating the algorithm-specific logic in separate classes, making
the system easier to maintain and test.

Detailed Explanation: A context class maintains a reference to a strategy interface. Concrete strategy classes
implement this interface with specific algorithms. The client sets the desired strategy at runtime.
interface PaymentStrategy {
Detailed Guide: 7 Major Design Patterns in Java

void pay(int amount);


}

class CreditCardPayment implements PaymentStrategy {


public void pay(int amount) {
System.out.println("Paid " + amount + " with Credit Card");
}
}

class PayPalPayment implements PaymentStrategy {


public void pay(int amount) {
System.out.println("Paid " + amount + " with PayPal");
}
}

class PaymentContext {
private PaymentStrategy strategy;

public void setStrategy(PaymentStrategy strategy) {


this.strategy = strategy;
}

public void pay(int amount) {


strategy.pay(amount);
}
}

6. Decorator Pattern

Purpose: Attach additional responsibilities to an object dynamically. The Decorator pattern provides a flexible
alternative to subclassing for extending functionality.

Significance: This pattern is particularly useful when you want to add responsibilities to objects without
affecting other objects of the same class. It promotes the Single Responsibility Principle by allowing
functionality to be divided into classes with specific responsibilities.

Detailed Explanation: In the Decorator pattern, an abstract component defines the interface, and concrete
components are extended by decorators. Each decorator wraps the component and adds new behavior
either before or after delegating to the original component.
interface Coffee {
String getDescription();
int getCost();
}

class BasicCoffee implements Coffee {


public String getDescription() { return "Basic Coffee"; }
public int getCost() { return 5; }
Detailed Guide: 7 Major Design Patterns in Java

class MilkDecorator implements Coffee {


private Coffee coffee;

public MilkDecorator(Coffee coffee) {


this.coffee = coffee;
}

public String getDescription() {


return coffee.getDescription() + ", Milk";
}

public int getCost() {


return coffee.getCost() + 2;
}
}

7. Adapter Pattern

Purpose: Convert the interface of a class into another interface that clients expect. This pattern lets classes
work together that couldn't otherwise because of incompatible interfaces.

Significance: The Adapter pattern is essential when integrating legacy components with new systems or
when using third-party libraries. It promotes the reuse of existing classes by converting their interfaces to a
more suitable form without modifying the original code.

Detailed Explanation: In this pattern, the adapter wraps the existing class (the adaptee) and translates the
interface into one expected by the client, allowing the two to work together seamlessly.
interface MediaPlayer {
void play(String fileName);
}

class MP3Player implements MediaPlayer {


public void play(String fileName) {
System.out.println("Playing MP3: " + fileName);
}
}

// Adaptee class with an incompatible interface


class VLCPlayer {
public void playVLC(String fileName) {
System.out.println("Playing VLC: " + fileName);
}
}

// Adapter class implements the target interface and translates the request to the adaptee
Detailed Guide: 7 Major Design Patterns in Java

class MediaAdapter implements MediaPlayer {


private VLCPlayer vlcPlayer;

public MediaAdapter() {
vlcPlayer = new VLCPlayer();
}

public void play(String fileName) {


vlcPlayer.playVLC(fileName);
}
}

This detailed guide provides an overview and examples of each design pattern, highlighting their importance
in writing clean, maintainable, and scalable code. By understanding these patterns, developers can better
apply them to solve complex design problems effectively.

You might also like