0% found this document useful (0 votes)
4 views14 pages

Design Pattern Notes

The document outlines various object-oriented design patterns, categorized into Creational, Structural, and Behavioral patterns. It provides detailed descriptions, use cases, and code examples for patterns such as Singleton, Factory, Adapter, and Strategy. Each pattern is explained with its purpose, key features, and implementation details, making it a comprehensive guide for understanding design patterns in software development.

Uploaded by

Rohit Kumar
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)
4 views14 pages

Design Pattern Notes

The document outlines various object-oriented design patterns, categorized into Creational, Structural, and Behavioral patterns. It provides detailed descriptions, use cases, and code examples for patterns such as Singleton, Factory, Adapter, and Strategy. Each pattern is explained with its purpose, key features, and implementation details, making it a comprehensive guide for understanding design patterns in software development.

Uploaded by

Rohit Kumar
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/ 14

Object-Oriented

Design Patterns

Patterns Covered

Creational: Singleton, Factory


Structural: Adapter, Facade, Proxy
Behavioral: Strategy, Template Method, Command, Observer, Iterator, State

Prepared by : Chamodya Hirusha


Category Pattern Purpose Use Case Key Feature

Database Private
Ensure a class has only
Creational Singleton connection, constructor, static
one instance
config manager instance

GUI elements, Delegates


Create objects without
Factory dynamic object instantiation to
specifying exact class
creation subclasses

Converts interface
Bridge between Legacy system
Structural Adapter to match client
incompatible interfaces integration
expectation

Simplify a complex Library wrapper, Provides


Facade system with a unified API simplified
interface simplification interface

Lazy loading, Surrogate or


Control access to
Proxy access control, placeholder for
another object
logging another object

Payment
Define interchangeable methods, Encapsulates
Behavioral Strategy
algorithms sorting algorithm logic
strategies

Define the skeleton of


Game loop, Abstract method
Template an algorithm and allow
report for steps, fixed
Method subclasses to fill in
generation structure
steps

Encapsulate requests Undo/redo, Decouples sender


Command
as objects remote controls and receiver

Sequential access to List, tree, or Unified way to


Iterator
elements in a collection graph traversal access elements

State-dependent
Change behavior when Media players,
State behavior without
internal state changes UI modes
conditionals

One-to-many
Notify multiple objects Event systems, relationship with
Observer
about state changes UI components automatic
notification
📝 Singleton Design Patterns
public class A { We have only one object per class, and
everyone should be able to use it. If we want to
private static A a;
🔒🧩
access a single component everywhere, we
can use the Singleton Design Pattern.
private A() {} // Private constructor
1️⃣ The class must be public.
public static A getA() { 2️⃣ It must have a private static variable.
if (a == null) { 3️⃣ It must have a private constructor.
a = new A();
}
return a;
}
}

class Test {
public static void main(String[] args) {
A a1 = A.getA();
A a2 = A.getA();

System.out.println("a1 == a2: " + (a1 == a2));


}
}

Visibility Member Description

Private instance: Singleton Static instance of the class

Private constructor to prevent


private Singleton() instantiation

Returns the single instance of the


public getInstance(): Singleton class

🌟 Separate 3 rows.
🌟 In the first row, write the class name, interface name, abstract class name.
🌟 In the second row, write the variables.
🌟 In the third row, write the method.
🌟 If underlined, it is static, if not underlined, it is instances.
🌟 (-) Mark private (+) Mark public
🌟 A colon (:) is used to indicate the data type.
🌟 The final keyword is indicated by an underscore (-) symbol.
🌟 Abstract class is indicated by italic type.
📝 Factory Design Pattern
interface Vehicle { Directly creating an object from a class is
public abstract void drive(); prohibited, and objects are created with
} logic from a factory.
class Car implements Vehicle {
@Override
public void drive() {
System.out.println("Driving a car...");
}
}

class Bike implements Vehicle {


@Override
public void drive() {
System.out.println("Riding a bike...");
}
}

class VehicleFactory {
public Vehicle makeVehicle(String type) {
if (type.equals("Car")) {
return new Car();
} else if (type.equals("Bike")) {
return new Bike();
} else {
return null;
}
}
}

class TestVehicle {
public static void main(String[] args) {
VehicleFactory factory = new VehicleFactory();
Vehicle v1 = factory.makeVehicle("Car");
v1.drive();
Vehicle v2 = factory.makeVehicle("Bike");
v2.drive();
}
}

Class / Interface Attributes Methods

Product (interface) - +operation()

Factory - +createProduct(type)

ConcreteProduct - +operation()
📝Adapter Design Pattern Notes

Class / Interface Attributes Methods

Target (interface) - + request()

Context - target: Target + setTarget(target: Target) + useTarget()

Adaptee - + specificRequest()

Adapter - adaptee: Adaptee + Adapter(adaptee: Adaptee) + request()

interface SD { void readSDCard(); } Adapter Is-A relationship sd


interface MicroSD { void readMicroSD(); } Adapter Has A relationship microsd

class Laptop {
private SD sd;
public void setSd(SD sd) { this.sd = sd; }
public void viewFile() { sd.readSDCard(); }
}

class SonySD implements SD {


public void readSDCard() { System.out.println("Reading Sony SD Card"); }
}

class SamsungMicroSD implements MicroSD {


public void readMicroSD() { System.out.println("Reading Micro SD Card"); }
}

class Adapter implements SD {


private MicroSD microSD;
public Adapter(MicroSD microSD) { this.microSD = microSD; }
public void readSDCard() { microSD.readMicroSD(); }
}

public class Test {


public static void main(String[] args) {
Laptop laptop = new Laptop();
laptop.setSd(new SonySD());
laptop.viewFile();

laptop.setSd(new Adapter(new SamsungMicroSD()));


laptop.viewFile();
}
}
📝 Facade Design Pattern
class A {
public void a1() { ✅ Simplifying a Complex Code for Others to Use Easily
System.out.println("A.a1"); 1️⃣ In large systems, multiple classes often work together, creating
} complexity for the user.
public void a2() { 2️⃣ To make it easier to use, group all related objects into a single
System.out.println("A.a2"); class that acts as a unified interface.
} 3️⃣ This single class—often called a Facade—hides the internal
} complexity and exposes only the necessary methods.
4️⃣ Clients interact with one object only, without needing to
class B { understand or manage the underlying subsystems.
public void b1() { 5️⃣ This approach improves code readability, reusability, and
System.out.println("B.b1"); maintainability, making the system easier to work with.
}
}

class C {
public void c1() {
System.out.println("C.c1");
}
}

class X {
private A a; Class Attributes Methods
private B b;
private C c;
- subsystem 1: Subsystem 1
+ Facade()
public X() { Facade - subsystem 2: Subsystem 2
+ operation()
a = new A(); - subsystem 3: Subsystem 3
b = new B();
c = new C();
} Subsystem 1 + operation 1()

public void x1() {


a.a1(); Subsystem 2 + operation 2()
b.b1();
c.c1();
a.a2();
} Subsystem 3 + operation 3()
}

public class Test {


public static void main(String[] args) {
X x = new X();
x.x1();
}
}
📝 Proxy Design Pattern
interface Image {
void display();
Client
}
Client Proxy
class RealImage implements Image {
private String filename; Database
Client

public RealImage(String filename) {


this.filename = filename;
loadFromDisk();
}

private void loadFromDisk() {


System.out.println("Loading image: " + filename);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

@Override
public void display() {
System.out.println("Displaying image: " + filename);
}
}

class ProxyImage implements Image { Class /


private String filename; Attributes Methods
Interface
private RealImage realImage;
public ProxyImage(String filename) {
this.filename = filename; Subject - +request()
}

@Override RealSubject - +request()


public void display() {
if (realImage == null) {
realImage = new RealImage(filename); Proxy -real: RealSubject +request()
}
realImage.display(); class Test {
} public static void main(String[] args) {
} System.out.println("Creating proxy images...");
Image img1 = new ProxyImage("photo1.jpg");
Image img2 = new ProxyImage("photo2.jpg");

System.out.println("\n--- First time display ---");


img1.display();

System.out.println("\n--- Second time display ---");


img1.display();

System.out.println("\n--- Display second image ---");


img2.display();
}
}
📝Strategy Design Pattern
At runtime, the Strategy Design Pattern lets you dynamically choose and apply different
algorithms or behaviors based on context or user input. This promotes loose coupling and
modularity by separating behavior from core logic, enabling easy swapping, extension, and
maintenance without changing existing code. It's ideal for payment processing, sorting, game AI,
or data formatting where behavior varies dynamically.

interface Strategy {
public boolean check(String text);
}

class SahanStrategy implements Strategy {


public boolean check(String text) {
return text.contains("j");
}
} Class / Interface Attributes Methods
class KasunStrategy implements Strategy {
public boolean check(String text) { Strategy (interface) - + execute()
boolean b = false;
for (int i = 0; i < text.length(); i++) {
if (text.charAt(i) == 'j') { ConcreteStrategyA - + execute()

b = true;
break; // Exit loop once 'j' is found ConcreteStrategyB - + execute()
}
}
+setStrategy(stra
return b; Context - strategy: Strategy tegy: Strategy)
} + useStrategy()
}
class Context {
private Strategy strategy;
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public boolean useStrategy(String text) {
return strategy.check(text);
}
}
class Test {
public static void main(String[] args) {
String text = "Hello Java";
Context context = new Context();
context.setStrategy(new SahanStrategy());
System.out.println("SahanStrategy result: " + context.useStrategy(text));
context.setStrategy(new KasunStrategy());
System.out.println("KasunStrategy result: " + context.useStrategy(text));
}
}
📝 Template Method Design Pattern
The class that designs the algorithm must
abstract class A { be an abstract class.
public final void process() { The method that writes the algorithm must
m();
be final.
n();
p();
}
private void m() {
System.out.println("m");
}

public abstract void n();

private void p() {


System.out.println("p");
}
}

class X extends A {
@Override
public void n() {
System.out.println("X.n");
}
}

class Test {
Real-World Analogy
public static void main(String[] args) {
A a = new X();
a.process();
}
}

Class / Interface Attributes Methods

AbstractClass - +templateMethod() #step()

ConcreteClass - Override steps


Real-World Analogy
abstract class DocumentPrinter {

public final void printDocumentProcess() {


selectDocument();
if (shouldAddWatermark()) {
addWatermark();
}
print();
finish();
}

protected abstract void selectDocument();

protected abstract void addWatermark();

private void print() { class ReportPrinter extends DocumentPrinter {


System.out.println("Printing document..."); @Override
} protected void selectDocument() {
System.out.println("Selected: Report.docx");
private void finish() { }
System.out.println("Print complete.\n");
} @Override
protected void addWatermark() {
public boolean shouldAddWatermark() { System.out.println("Added watermark:
return true; 'Internal Use Only'");
} }
} }

// Concrete classes class ResumePrinter extends DocumentPrinter {


@Override
class InvoicePrinter extends DocumentPrinter { protected void selectDocument() {
@Override System.out.println("Selected: Resume.pdf");
protected void selectDocument() { }
System.out.println("Selected: Invoice.pdf");
} @Override
protected void addWatermark() {
@Override // No watermark added for resumes
protected void addWatermark() { }
System.out.println
("Added watermark: 'Company Confidential'"); @Override
} public boolean shouldAddWatermark() {
} return false;
}
}

class TestPrinter {
public static void main(String[] args) {
DocumentPrinter p1 = new InvoicePrinter();
p1.printDocumentProcess();

DocumentPrinter p2 = new ReportPrinter();


p2.printDocumentProcess();

DocumentPrinter p3 = new ResumePrinter();


p3.printDocumentProcess();
}
}
📝 Command Design Pattern
Decouples Sender and Receiver: Separates the object that invokes the operation from the one that
knows how to perform it

interface Command {
void execute();
}

class Robot {
void walk() {
System.out.println("Robot is walking");
}
void speak() {
System.out.println("Robot is speaking");
}
}

class WalkCommand implements Command { class Invoker {


private Robot robot; private Command command;
public WalkCommand(Robot robot) { void setCommand(Command command) {
this.robot = robot; this.command = command;
} }
public void execute() { void invoke() {
robot.walk(); command.execute();
} }
} }

class SpeakCommand implements Command { class Test {


private Robot robot; public static void main(String[] args) {
public SpeakCommand(Robot robot) { Robot r = new Robot();
this.robot = robot; Command walk = new WalkCommand(r);
}
Command speak = new SpeakCommand(r);
public void execute() {
robot.speak();
}
Invoker inv = new Invoker();
} inv.setCommand(walk);
inv.invoke();

inv.setCommand(speak);
inv.invoke();
}
}

Class / Interface Attributes Methods

Command - +execute()

ConcreteCommand -receiver +execute()

Invoker -command +setCommand() +invoke()

Receiver - +action()
📝 Iterator Design Pattern
The common model for reading any collection is to use an
interface BookIterator { iterator.
boolean hasNext(); This pattern is only relevant for collections.
Object next();
}

class ArrayBookIterator implements BookIterator {


private String[] books;
private int index;

public ArrayBookIterator(String[] books) {


this.books = books; Class / Interface Attributes Methods
}

public boolean hasNext() { Iterator - +hasNext()


return index < books.length; +next()
}
ConcreteIterator -collection +hasNext()
public Object next() { +next()
return books[index++];
} Collection - +createIterator()
}

class ListBookIterator implements BookIterator {


private List<String> books;
private int index;

public ListBookIterator(List<String> books) {


this.books = books;
}

public boolean hasNext() {


return index < books.size();
}

public Object next() {


return books.get(index++);
}
}
class Test {
public static void main(String[] args) {
String[] arrayBooks = {"Math", "Science", "English"};
List<String> listBooks = Arrays.asList("History", "Geography", "Art");

BookIterator aIter = new ArrayBookIterator(arrayBooks);


BookIterator lIter = new ListBookIterator(listBooks);

while (aIter.hasNext()) System.out.println(aIter.next());


while (lIter.hasNext()) System.out.println(lIter.next());
}
}
📝 State Design Pattern
interface Animal {
public abstract void makeSound();
}

class Lion implements Animal {


@Override
public void makeSound() {
System.out.println("Roar!");
}
}

class Elephant implements Animal {


@Override
public void makeSound() {
System.out.println("Trumpet!");
}
}

class Zookeeper {
private Animal animal;

public void setAnimal(Animal animal) {


this.animal = animal;
}

public void commandSound() {


this.animal.makeSound();
}
}

class TestZoo {
public static void main(String[] args) {
Zookeeper zookeeper = new Zookeeper();

Animal lion = new Lion();


Animal elephant = new Elephant();

zookeeper.setAnimal(lion);
zookeeper.commandSound();

zookeeper.setAnimal(elephant);
zookeeper.commandSound();
}
}
Class / Interface Attributes Methods

State - +handle()

ConcreteState - Implements handle()

Context -state: State +setState() +request()


📝 Observer Design Pattern
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}

class TemperatureSensor implements Subject {


private ArrayList<Observer> observers = new ArrayList<>();
private int temperature;
class DisplayDevice implements Observer {
@Override @Override
public void registerObserver(Observer o) { public void update(int temp) {
observers.add(o); int t = temp;
} System.out.println("T: " + t + "°C");
}
@Override }
public void removeObserver(Observer o) {
observers.remove(o); class AlertSystem implements Observer {
} @Override
public void update(int temp) {
@Override if (temp > 30) {
public void notifyObservers() { int t = temp;
for (Observer o : observers) { System.out.println("HT: " + t + "°C");
o.update(temperature); }
} }
} }

public void setTemperature(int temp) { public class Main {


this.temperature = temp; public static void main(String[] args) {
notifyObservers(); TemperatureSensor sensor = new
} TemperatureSensor();
Observer display = new DisplayDevice();
public int getTemperature() { Observer alert = new AlertSystem();
return temperature;
} sensor.registerObserver(display);
} sensor.registerObserver(alert);

interface Observer { sensor.setTemperature(25);


void update(int temp); sensor.setTemperature(35);
} }
}

Class / Interface Attributes Methods

Subject -observers: List +register() +remove() +notify()

Observer - +update()

ConcreteSubject -state +setState() +getState()

ConcreteObserver - Implements update()

You might also like