0% found this document useful (0 votes)
22 views30 pages

Adapter Pattern

Uploaded by

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

Adapter Pattern

Uploaded by

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

Singleton Pattern:

Singleton pattern only allows creation of only one object from a class. It
won’t create any new object even if it is frequently called using the new
keyword, it only returns the single object that was created.

For example:

Dhoro ekta boro office e ekjon Boss ache j shob team er upor control
rakhe.

Ekhon prottek team jodi nijer nijer boss niye ney tahole office e juddho
lagbe!

So, Singleton Pattern says:

“I will create only one Boss,

So, whoever requires will use only one boss.”


Ques: You are building a logger system where only one instance should exist
across the application.

Implement the Singleton Design Pattern so that:

- Only one object of Logger can be created.


- It should provide a method log(String message) to print logs.
- The main function show that both calls return the same object.

Code:

// Singleton Logger Class

class Logger {

private static Logger instance;


private Logger() {

System.out.println("Logger Initialized.");

public static Logger getInstance() {

if (instance == null) {

instance = new Logger();

return instance;

public void log(String message) {

System.out.println("[LOG] " + message);

// Main Driver Class

public class Main {

public static void main(String[] args) {

Logger logger1 = Logger.getInstance();

logger1.log("User logged in");

Logger logger2 = Logger.getInstance();

logger2.log("User made a payment");

System.out.println("Same object? " + (logger1 == logger2));

}
}

How the Singleton Pattern is used in this scenario:

1. We create a private constructor, ensuring no ‘new Logger(), command


can be explicitly called.
- private logger() { }
2. Created a static instance variable, so every other classes can use this
object.
- private static Logger instance;
3. Object is accessed using public static method. The first time
getInstance() is called, it creates an object. Later the object can be
called from anywhere and it returns the same object everytime.

Singleton Design Pattern is applied here to make sure that the Logger object
is created only once and shared across the whole application. This avoids
inconsistency and ensures centralized control over logging.

Factory Pattern:
Imagine you own a vehicle factory. Customer visits and asks for different
types of vehicle like, ‘car’, ‘truck’, ‘bike’, etc. Now when you send a request
to the factory for manufacture, you only say the type of vehicle and the
factory prepares it for you.
Q: You are designing a vehicle rental system where users can
request different types of vehicles like Car and Bike.
Use the Factory Design Pattern to implement the following:

 A Vehicle interface

 Two classes: Car and Bike that implement Vehicle

 A VehicleFactory that creates the object

 A driver class that takes user input and shows the vehicle output.

// Step 1: Interface

interface Vehicle {

void start();

// Step 2: Concrete Classes

class Car implements Vehicle {


public void start() {

System.out.println("Car started!");

class Bike implements Vehicle {

public void start() {

System.out.println("Bike started!");

// Step 3: Factory Class

class VehicleFactory {

public static Vehicle getVehicle(String type) {

if (type.equalsIgnoreCase("Car")) {

return new Car();

} else if (type.equalsIgnoreCase("Bike")) {

return new Bike();

} else {

return null;

public class Main {

public static void main(String[] args) {

Vehicle v1 = VehicleFactory.getVehicle("Car");

v1.start();
Vehicle v2 = VehicleFactory.getVehicle("Bike");

v2.start();

Explain how the Factory Design Pattern is applied in this scenario:

The Factory Design Pattern is applied here to delegate the responsibility


of object creation to a factory class (VehicleFactory).
It hides the instantiation logic from the client.
The client only provides the type of object needed and receives a fully
constructed object, maintaining loose coupling and easy scalability.

Builder Pattern:
Builder Pattern is used when a complex object is built step by step.

For example:

Dhoro customer chailo, “Amake burger dao, lettuce diba, sauce diba,
cheese diba.”

So, builder pattern builds it like:

Burger burger = new Burger.Builder()

.addCheese()

.addLettuce()

.addSauce()

.build();
Q: You are building a meal-ordering system. A meal may have
optional items such as drink, dessert, salad, and main course.
Implement this using the Builder Pattern so that:

 Each meal is built step by step.

 The builder supports method chaining.

 The final object is created using a build() method.

 Demonstrate it using a main function.


// Product Class

class Meal {

private boolean drink;

private boolean dessert;

private boolean salad;

private boolean mainCourse;

private Meal(Builder builder) {

this.drink = builder.drink;

this.dessert = builder.dessert;

this.salad = builder.salad;

this.mainCourse = builder.mainCourse;

public void showItems() {

System.out.println("Meal includes:");

if (drink) System.out.println("- Drink");

if (dessert) System.out.println("- Dessert");

if (salad) System.out.println("- Salad");

if (mainCourse) System.out.println("- Main Course");

// Builder Class

static class Builder {

private boolean drink;

private boolean dessert;


private boolean salad;

private boolean mainCourse;

public Builder addDrink() {

this.drink = true;

return this;

public Builder addDessert() {

this.dessert = true;

return this;

public Builder addSalad() {

this.salad = true;

return this;

public Builder addMainCourse() {

this.mainCourse = true;

return this;

public Meal build() {

return new Meal(this);

}
}

public class Main {

public static void main(String[] args) {

Meal myMeal = new Meal.Builder()

.addDrink()

.addMainCourse()

.addDessert()

.build();

myMeal.showItems();

Builder Pattern is used in this code for meal customization. Meal.Builder


allows user to add items step by step. The .build() method returns the final
object.

Abstract Factory Pattern:


Creates a full group of objects of same style and theme, but client doesn’t
know what classes are used.

Example imagine client asked for sofa, table, and a chair, and tells that the
design has to be modern and wants Victorian design chair.
Now you know all those have to be of the same design and if chair Victorian,
sofa is as well, and there is no mismatch.

Therefore:

- Abstract Factory → FurnitureFactory


- Concrete Factories → ModernFactory, VictorianFactory
- Abstract Products → Chair, Sofa
- Concrete Products → ModernChair, VictorianSofa etc.

// Abstract Products

interface Chair {

void sitOn();

interface Sofa {

void lieOn();

}
// Concrete Products - Modern

class ModernChair implements Chair {

public void sitOn() {

System.out.println("Sitting on a Modern Chair");

class ModernSofa implements Sofa {

public void lieOn() {

System.out.println("Lying on a Modern Sofa");

// Concrete Products - Victorian

class VictorianChair implements Chair {

public void sitOn() {

System.out.println("Sitting on a Victorian Chair");

class VictorianSofa implements Sofa {

public void lieOn() {

System.out.println("Lying on a Victorian Sofa");

// Abstract Factory
interface FurnitureFactory {

Chair createChair();

Sofa createSofa();

// Concrete Factories

class ModernFurnitureFactory implements FurnitureFactory {

public Chair createChair() {

return new ModernChair();

public Sofa createSofa() {

return new ModernSofa();

class VictorianFurnitureFactory implements FurnitureFactory {

public Chair createChair() {

return new VictorianChair();

public Sofa createSofa() {

return new VictorianSofa();

public class Main {

public static void main(String[] args) {

FurnitureFactory factory = new ModernFurnitureFactory();

Chair chair = factory.createChair();


Sofa sofa = factory.createSofa();

chair.sitOn();

sofa.lieOn();

// You can switch factory without changing rest of the code

factory = new VictorianFurnitureFactory();

factory.createChair().sitOn();

factory.createSofa().lieOn();

- In this code we have use different design variant for Chair and Sofa.
Abstract Factory (FurnitureFactory) can help us create a full set design
of the same family (Modern and Victorian).

Adapter Pattern:
Adapter Pattern is used when the interface of two systems don’t match and
we use ‘adapter’ to match them.

Example:

- Imagine tomar kaache 3 pin plug ache but tomar room e 2 pin er
socket. Therefore tomar ekta adapter dorkar jeta 3 pin k 2 pin e
convert kore dey.
Q: You have a legacy OldSystem class with a method fetchOldData().
But the client expects to call a method fetchData().
Use Adapter Pattern so that the new system can interact with the
old one without changing its code.
Implement with:

 The old class (OldSystem)

 A target interface (DataFetcher)

 An adapter class (DataAdapter)

 Main function to demonstrate usage

// Old/Legacy class

class OldSystem {

public void fetchOldData() {


System.out.println("Fetching data from Old System.");

// Target Interface (what client expects)

interface DataFetcher {

void fetchData();

// Adapter class

class DataAdapter implements DataFetcher {

private OldSystem oldSystem;

public DataAdapter(OldSystem oldSystem) {

this.oldSystem = oldSystem;

public void fetchData() {

oldSystem.fetchOldData(); // adapting method call

public class Main {

public static void main(String[] args) {

OldSystem legacy = new OldSystem();

DataFetcher adapter = new DataAdapter(legacy); // adapter in action


adapter.fetchData(); // calling in new way, using old system

How is Adapter Pattern applied?


In this code client wants to fethData() but the legacy system has
fetchOldData(). This is why we use Adapter Pattern. DataAdapter class wraps
the old system and behaves like an interface which the client expects. Client
doesn’t know that internally it calls the fetchOldData().

Decorator Pattern:
We use decorator pattern when we want to add new features without
modifying the original class.

Example:

Dhoro tumi ekta pizza shop chalao, customer ke plain pizza dao. Kintu ekhon
customer bole:

“Cheese lagbe”

“Mushroom lagbe”

“Pepperoni o lagbe”

Ekhon tumi plainPizza class k manage na kore tumi Decorator diye bolcho:

- CheeseDecorator wraps PlainPizza


- MushroomDecorator wraps CheeseDecorator
- PepperoniDecorator wraps MushroomDecorator

Ekhane sob toppings independently add hoy, cost calculate kore


ar object ke dynamically decorate kore!
Q: You are tasked with designing a Pizza ordering system where
customers can customize their pizzas by adding toppings such as
cheese, pepperoni, and mushrooms.
Each topping increases the cost of the pizza.
Implement this using the Decorator Design Pattern so that:

 The base pizza class represents a simple pizza with a default cost

 Each topping is a decorator class

 Toppings can be added dynamically without modifying the base class

 Demonstrate using a driver class

// Step 1: Pizza Interface

interface Pizza {

String getDescription();
double getCost();

// Step 2: Concrete Pizza Class

class PlainPizza implements Pizza {

public String getDescription() {

return "Plain Pizza";

public double getCost() {

return 5.0;

// Abstract Decorator

abstract class PizzaDecorator implements Pizza {

protected Pizza pizza;

public PizzaDecorator(Pizza pizza) {

this.pizza = pizza;

// Cheese Topping

class CheeseDecorator extends PizzaDecorator {

public CheeseDecorator(Pizza pizza) {

super(pizza);

}
public String getDescription() {

return pizza.getDescription() + ", Cheese";

public double getCost() {

return pizza.getCost() + 1.5;

// Mushroom Topping

class MushroomDecorator extends PizzaDecorator {

public MushroomDecorator(Pizza pizza) {

super(pizza);

public String getDescription() {

return pizza.getDescription() + ", Mushroom";

public double getCost() {

return pizza.getCost() + 2.0;

// Pepperoni Topping

class PepperoniDecorator extends PizzaDecorator {


public PepperoniDecorator(Pizza pizza) {

super(pizza);

public String getDescription() {

return pizza.getDescription() + ", Pepperoni";

public double getCost() {

return pizza.getCost() + 2.5;

public class Main {

public static void main(String[] args) {

// Step-by-step build

Pizza myPizza = new PlainPizza();

myPizza = new CheeseDecorator(myPizza);

myPizza = new MushroomDecorator(myPizza);

myPizza = new PepperoniDecorator(myPizza);

System.out.println("Order: " + myPizza.getDescription());

System.out.println("Total Cost: $" + myPizza.getCost());

How is Decorator Pattern applied?


This system has a PlainPizza class that represents the base pizza. Toppings
are created as decorator class that implements the pizza interface and wraps
the existing pizza object. Each topping individually adds cost and extends
description.

Strategy Pattern:
We use strategy pattern when we want to change an objects behavior or
algorithm during runtime.

For example:

Dhoro tumi ekta travel app banaccho. User bole, “Ami University jabo but bus
e, ba train-e, ba uber-e jabo.

You design the travel system this way:

- TravelStrategy = common interface


- BusStrategy, UberStrategy, TrainStrategy = different ways to
travel
- Main class e user chaile strategy change korte pare — without
changing the main code
Q: You are building a travel app where users can choose different
travel methods: Bus, Uber, or Train.
Implement the Strategy Design Pattern so that:

 There is a TravelStrategy interface

 Multiple concrete strategies implement the interface

 A context class uses a selected strategy

 Demonstrate changing strategy at runtime in the main class

// Strategy Interface

interface TravelStrategy {

void travel();

// Concrete Strategies

class BusStrategy implements TravelStrategy {


public void travel() {

System.out.println("Traveling by Bus...");

class UberStrategy implements TravelStrategy {

public void travel() {

System.out.println("Traveling by Uber...");

class TrainStrategy implements TravelStrategy {

public void travel() {

System.out.println("Traveling by Train...");

// Context Class

class Traveler {

private TravelStrategy strategy;

public void setStrategy(TravelStrategy strategy) {

this.strategy = strategy;

public void startTravel() {

strategy.travel();

}
}

public class Main {

public static void main(String[] args) {

Traveler person = new Traveler();

person.setStrategy(new BusStrategy());

person.startTravel();

person.setStrategy(new UberStrategy());

person.startTravel();

person.setStrategy(new TrainStrategy());

person.startTravel();

How is Strategy Pattern applied?


In this code, TravelStrategy interface allows user to select the travel method.
Bus, uber, train have been defined in separate classes. If user wants he/she
can change strategy dynamically inside traveler class and use it for
travelling.

Observer Pattern:
Observer Pattern is used when you want to notify many other objects when
there is a change in the main object.
Example;

Dhoro tumi ekta youtube channel chalao and onno manush tomake subscribe
kore. Everytime tumi new video upload koro tomar subscribers ra notification
pay. Ekhane YouTube channel hocche subject r subscribers ra hocche
observers. And j subscribers der notify kora hocche sheta observer pattern.

Q: You are building a notification system for a news website.


Users can subscribe to news updates.
When a new article is published, all subscribers should
automatically get notified.
Use the Observer Design Pattern to implement this. Include:

 A Subject interface and Observer interface

 Concrete classes implementing both


 A main class to demonstrate subscription and notification

// Observer Interface

interface Observer {

void update(String news);

// Subject Interface

interface Subject {

void subscribe1(Observer o);

void subscribe2(Observer o);

void notifyObservers();

// Concrete Subject

class NewsAgency implements Subject {

private Observer observer1;

private Observer observer2;

private String latestNews;

public void subscribe1(Observer o) {

this.observer1 = o;

public void subscribe2(Observer o) {

this.observer2 = o;

}
public void notifyObservers() {

if (observer1 != null) {

observer1.update(latestNews);

if (observer2 != null) {

observer2.update(latestNews);

public void newArticle(String news) {

this.latestNews = news;

notifyObservers();

// Concrete Observer

class NewsReader implements Observer {

private String name;

public NewsReader(String name) {

this.name = name;

public void update(String news) {

System.out.println(name + " got news: " + news);

}
public class Main {

public static void main(String[] args) {

NewsAgency agency = new NewsAgency();

Observer reader1 = new NewsReader("Alice");

Observer reader2 = new NewsReader("Bob");

agency.subscribe1(reader1);

agency.subscribe2(reader2);

agency.newArticle("Big Breaking!");

How is Observer Pattern applied?


Here NewsAgency is working as a subject in this code, who manages a list of
subscribers (Observers). When there is a newArticle(), Subject notifies to all
its readers. Observer pattern is used here to send automatic updates without
tight coupling.

You might also like