[Go to site: main page, start]

0% found this document useful (0 votes)
16 views13 pages

Java Design Patterns Overview

The document outlines various Java design patterns, including Singleton, Factory, Builder, Prototype, Observer, Decorator, and Adapter patterns, detailing their concepts, implementations, and use cases. Each pattern is accompanied by example code and interview questions to assess understanding. A comparison table summarizes the purpose and appropriate usage scenarios for each design pattern.

Uploaded by

Jha Avinash
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)
16 views13 pages

Java Design Patterns Overview

The document outlines various Java design patterns, including Singleton, Factory, Builder, Prototype, Observer, Decorator, and Adapter patterns, detailing their concepts, implementations, and use cases. Each pattern is accompanied by example code and interview questions to assess understanding. A comparison table summarizes the purpose and appropriate usage scenarios for each design pattern.

Uploaded by

Jha Avinash
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

Java Design Patterns

1. Singleton Pattern
Concept:

●​ Ensures that a class has only one instance and provides a global point of access
to it.
●​ Used when only one object should control the entire application's behavior (e.g.,
logging, database connection, configuration manager).

Implementation:

Eager Initialization (Thread-safe but may create unused instance)


java

class Singleton {
private static final Singleton instance = new Singleton(); //
Instance created eagerly
private Singleton() {} // Private constructor prevents
instantiation
public static Singleton getInstance() {
return instance;
}
}

Lazy Initialization (Not thread-safe)


java

class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton(); // Creates instance only
when needed
}
return instance;
}
}
Thread-safe Singleton (Double-Checked Locking)
java

class Singleton {
private static volatile Singleton instance;

private Singleton() {}

public static Singleton getInstance() {


if (instance == null) {
synchronized ([Link]) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

Best Approach: Using Enum (Recommended)


java

enum Singleton {
INSTANCE;

public void show() {


[Link]("Singleton using Enum");
}
}

Interview Questions:

1.​ Why should we use the Singleton pattern?


2.​ What are the different ways to implement Singleton?
3.​ What is the issue with lazy initialization in a multithreading environment?
4.​ How does volatile help in Singleton implementation?
5.​ Why is an Enum the best way to implement Singleton?
2. Factory Pattern
Concept:

●​ Used to create objects without exposing the creation logic to the client.
●​ Helps in handling object creation based on conditions.

Implementation:
java

// Step 1: Create an interface


interface Shape {
void draw();
}

// Step 2: Implement concrete classes


class Circle implements Shape {
public void draw() {
[Link]("Drawing Circle");
}
}

class Rectangle implements Shape {


public void draw() {
[Link]("Drawing Rectangle");
}
}

// Step 3: Create Factory class


class ShapeFactory {
public static Shape getShape(String type) {
if ([Link]("CIRCLE")) {
return new Circle();
} else if ([Link]("RECTANGLE")) {
return new Rectangle();
}
return null;
}
}

// Step 4: Usage
public class FactoryPatternDemo {
public static void main(String[] args) {
Shape shape1 = [Link]("CIRCLE");
[Link]();

Shape shape2 = [Link]("RECTANGLE");


[Link]();
}
}

Interview Questions:

1.​ What is the Factory pattern, and where is it used?


2.​ How is the Factory pattern different from the Singleton pattern?
3.​ Can we use Generics in the Factory pattern?
4.​ How does the Factory pattern help in Open/Closed Principle?

3. Builder Pattern
Concept:

●​ Used to construct complex objects step by step.


●​ Useful when a class has multiple optional parameters.

Implementation:
java

class Computer {
// Required parameters
private String CPU;
private int RAM;

// Optional parameters
private boolean isGraphicsCardEnabled;
private boolean isBluetoothEnabled;

private Computer(ComputerBuilder builder) {


[Link] = [Link];
[Link] = [Link];
[Link] = [Link];
[Link] = [Link];
}

public static class ComputerBuilder {


private String CPU;
private int RAM;
private boolean isGraphicsCardEnabled;
private boolean isBluetoothEnabled;

public ComputerBuilder(String CPU, int RAM) {


[Link] = CPU;
[Link] = RAM;
}

public ComputerBuilder setGraphicsCardEnabled(boolean


isGraphicsCardEnabled) {
[Link] = isGraphicsCardEnabled;
return this;
}

public ComputerBuilder setBluetoothEnabled(boolean


isBluetoothEnabled) {
[Link] = isBluetoothEnabled;
return this;
}

public Computer build() {


return new Computer(this);
}
}
}

// Usage
public class BuilderPatternDemo {
public static void main(String[] args) {
Computer computer = new [Link]("Intel i7",
16)
.setGraphicsCardEnabled(true)
.setBluetoothEnabled(false)
.build();
}
}
Interview Questions:

1.​ What problem does the Builder pattern solve?


2.​ How is it different from the Factory pattern?
3.​ How does the Builder pattern support immutability?
4.​ Can we modify the Builder class after creating an object?

4. Prototype Pattern
Concept:

●​ Creates objects by copying an existing object instead of creating new instances.

Implementation:
java

class Prototype implements Cloneable {


String name;

public Prototype(String name) {


[Link] = name;
}

@Override
protected Prototype clone() throws CloneNotSupportedException {
return (Prototype) [Link]();
}
}

public class PrototypePatternDemo {


public static void main(String[] args) throws
CloneNotSupportedException {
Prototype p1 = new Prototype("Original");
Prototype p2 = [Link]();

[Link]([Link]);
[Link]([Link]);
}
}
Interview Questions:

1.​ How does the Prototype pattern work?


2.​ What is the difference between shallow copy and deep copy?
3.​ How can we implement deep cloning in Java?

5. Observer Pattern
Concept:

●​ Used when one object (Subject) needs to notify multiple dependent objects
(Observers) about state changes.

Implementation:
java

import [Link];
import [Link];

// Observer interface
interface Observer {
void update(String message);
}

// Concrete Observer
class User implements Observer {
private String name;

public User(String name) {


[Link] = name;
}

@Override
public void update(String message) {
[Link](name + " received message: " + message);
}
}

// Subject class
class Channel {
private List<Observer> observers = new ArrayList<>();
public void subscribe(Observer observer) {
[Link](observer);
}

public void notifyObservers(String message) {


for (Observer observer : observers) {
[Link](message);
}
}
}

// Usage
public class ObserverPatternDemo {
public static void main(String[] args) {
Channel channel = new Channel();

Observer user1 = new User("Alice");


Observer user2 = new User("Bob");

[Link](user1);
[Link](user2);

[Link]("New Video Uploaded!");


}
}

Interview Questions:

1.​ What is the Observer pattern?


2.​ What is the difference between the Observer and Publisher-Subscriber patterns?

6. Decorator Pattern
Concept:

●​ Used to dynamically add behaviors to objects without modifying their code.


●​ Follows Open/Closed Principle (open for extension, closed for modification).

Use Case:
●​ When we want to extend functionality of classes without altering their structure.
●​ Example: Adding extra features to coffee (like sugar, milk) without modifying the
base Coffee class.

Implementation:
java

// Step 1: Create Component Interface


interface Coffee {
String getDescription();
double cost();
}

// Step 2: Concrete Component


class SimpleCoffee implements Coffee {
public String getDescription() {
return "Simple Coffee";
}

public double cost() {


return 50;
}
}

// Step 3: Decorator Abstract Class


abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;

public CoffeeDecorator(Coffee coffee) {


[Link] = coffee;
}

public String getDescription() {


return [Link]();
}

public double cost() {


return [Link]();
}
}
// Step 4: Concrete Decorators
class Milk extends CoffeeDecorator {
public Milk(Coffee coffee) {
super(coffee);
}

public String getDescription() {


return [Link]() + ", Milk";
}

public double cost() {


return [Link]() + 10;
}
}

class Sugar extends CoffeeDecorator {


public Sugar(Coffee coffee) {
super(coffee);
}

public String getDescription() {


return [Link]() + ", Sugar";
}

public double cost() {


return [Link]() + 5;
}
}

// Step 5: Usage
public class DecoratorPatternDemo {
public static void main(String[] args) {
Coffee coffee = new SimpleCoffee();
[Link]([Link]() + " = Rs." +
[Link]());

coffee = new Milk(coffee);


[Link]([Link]() + " = Rs." +
[Link]());
coffee = new Sugar(coffee);
[Link]([Link]() + " = Rs." +
[Link]());
}
}

Output:
java

Simple Coffee = Rs.50.0


Simple Coffee, Milk = Rs.60.0
Simple Coffee, Milk, Sugar = Rs.65.0

Interview Questions:

1.​ What is the purpose of the Decorator pattern?


2.​ How is it different from inheritance?
3.​ Where is the Decorator pattern used in Java?
4.​ Can we have multiple decorators applied at once?

7. Adapter Pattern
Concept:

●​ Converts one interface into another so that two incompatible interfaces can work
together.
●​ Acts as a bridge between two classes.

Use Case:

●​ When we need to use a legacy class with a new system.


●​ Example: Suppose we have an OldCharger with a roundPin(), but we need a
charger that supports flatPin(). The Adapter helps convert it.

Implementation:
java

// Step 1: Create Target Interface


interface NewCharger {
void chargeWithFlatPin();
}

// Step 2: Adaptee (Old Interface)


class OldCharger {
public void chargeWithRoundPin() {
[Link]("Charging with Round Pin");
}
}

// Step 3: Adapter Class


class ChargerAdapter implements NewCharger {
private OldCharger oldCharger;

public ChargerAdapter(OldCharger oldCharger) {


[Link] = oldCharger;
}

public void chargeWithFlatPin() {


[Link]("Adapter converts flat pin to round
pin...");
[Link]();
}
}

// Step 4: Usage
public class AdapterPatternDemo {
public static void main(String[] args) {
OldCharger oldCharger = new OldCharger();
NewCharger newCharger = new ChargerAdapter(oldCharger);

[Link]();
}
}

Output:

Adapter converts flat pin to round pin...


Charging with Round Pin
Interview Questions:

1.​ What is the Adapter pattern, and why is it used?


2.​ What are the types of Adapter patterns?
○​ Class Adapter (uses inheritance)
○​ Object Adapter (uses composition)
3.​ How is the Adapter pattern different from the Decorator pattern?
4.​ Can the Adapter pattern be used with multiple incompatible interfaces?

Comparison of Design Patterns:


Pattern Purpose When to Use?

Singleton Ensures one instance of a When a single control point is needed (e.g.,
class database connection, logging)

Factory Creates objects based on When object creation logic is complex or


conditions depends on user input

Builder Constructs objects step by When an object has many optional


step parameters

Prototyp Creates objects by cloning When object creation is expensive and


e existing ones duplication is required

Observer Notifies dependent objects When multiple objects should react to one
about state changes object's changes (e.g., event listeners)

Decorato Adds behavior dynamically When we want to enhance functionality


r to an object without modifying the base class

Adapter Converts one interface into When we need to integrate incompatible


another systems

Common questions

Powered by AI

The Adapter pattern converts an interface of a class into another interface that clients expect, which bridges the gap between incompatible systems, facilitating interoperability. While both Adapter and Decorator patterns change or add functionality, the Adapter pattern focuses on making two incompatible interfaces work together, whereas the Decorator pattern enhances or modifies object behaviors without changing the core interface .

The Prototype pattern handles object creation by cloning an existing object, as opposed to the Factory and Builder patterns which create instances from scratch based on certain parameters or logic. This approach is advantageous when the object creation is resource-intensive and the duplicate objects share many properties of the existing instance. It reduces the overhead of instantiating objects individually and allows for easier modification and extension of existing objects .

The Builder pattern supports immutability by constructing the final object step by step and returning a fully constructed immutable object. Once built, its state cannot be changed, aligning with the principle of immutability. Unlike the Factory pattern, which focuses on creating various subtypes of a type, the Builder pattern allows finer control over the construction process, especially useful for creating objects with numerous optional parameters .

Lazy initialization creates the Singleton instance only when it is needed, which saves resources but can lead to complications in multithreading environments because it is not inherently thread-safe, leading to potential race conditions. Eager initialization creates the instance at class loading time, which is thread-safe and avoids these issues but can lead to resource wastage if the instance is never used .

The enum approach is recommended for implementing a Singleton pattern in Java because it is inherently thread-safe and protects against serialization vulnerabilities. Unlike other methods, like eager initialization or lazy initialization with double-checked locking, using an enum ensures that the Singleton instance is not recreated even during serialization or reflection attacks, thus maintaining a strict one-instance nature of the class .

Implementing the Prototype pattern using the Cloneable interface highlights Java's capability to duplicate objects via the cloning process. Shallow copying, which the default clone() method performs, duplicates object references rather than deep cloning. Deep cloning requires custom implementation for comprehensive object duplication, affecting memory management by potentially increasing memory usage if not managed wisely, due to duplicate objects in memory .

The Observer pattern provides a model where an object (Subject) maintains a list of dependents (Observers) and notifies them of any state changes, similar to an event listener model where multiple listeners respond to events from a single source. This pattern allows decoupling between the observed subject and its observers, simplifying the management of dependencies and reactions to state changes .

The Factory pattern maintains the Open/Closed Principle by encapsulating object creation logic, allowing new types to be added with minimal change to existing code, thereby facilitating scalability. It effectively abstracts the instantiation logic, which supports flexibility in object creation but may lead to complexity if the number of product variants becomes large, necessitating careful management of factory logic .

Double-checked locking is intended to reduce the overhead of acquiring a lock by first checking the Singleton instance without synchronization. However, it relies on the volatile keyword to ensure thread-safety by guaranteeing visibility of changes to variables across threads. While it can improve performance by minimizing the lock acquisition, incorrect implementation can lead to subtle errors due to compiler optimizations or runtime reordering in multithreaded environments .

The Decorator pattern achieves adherence to the Open/Closed Principle by allowing new functionality to be added to objects dynamically without altering their code, thus keeping the class implementation closed to modification but open to extension. This improves code maintainability as modifications or enhancements can be implemented through new decorators instead of altering existing class structures .

You might also like