Software Design and DevelopmentUnit 617 min read
OO Design & Patterns: Classes, Inheritance, SOLID, GoF Patterns
Unit 6 of Software Design and Development covers object-oriented design principles (encapsulation, inheritance, polymorphism), SOLID principles for maintainable code, and Gang of Four design patterns (creational, structural, behavioral) with UML diagrams and real-world applications in Nepalese software systems.
TAKEAWAYS:
- Object-oriented design organizes software into reusable classes with relationships (inheritance, composition) to model real-world entities like Daraz’s product catalog or Ncell’s billing system.
- SOLID principles (Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion) prevent code rot in large systems like eSewa’s payment gateway.
- Design patterns (Singleton for database connections, Observer for live traffic updates, Strategy for discount calculations) solve recurring problems in apps like Pathao’s ride-matching or NEPSE’s stock trading.
- UML class diagrams visually represent inheritance hierarchies (e.g.,
Vehicle → Car → ElectricCar) and associations (e.g.,User1-to-manyOrder). - Refactoring legacy code using patterns improves performance (e.g., Flyweight for Daraz’s product thumbnails) and scalability (e.g., Proxy for lazy-loading Ncell’s customer data).
- Exam questions test pattern identification in scenarios (e.g., "Which GoF pattern would you use for a Kathmandu traffic route optimizer?"), so memorize use cases and UML symbols.
Core Concepts: Classes, Objects, and the "Big Three" OO Principles
Object-Oriented Design (OOD) treats software as a network of interacting objects (instances of classes) that encapsulate data and behavior. Unlike procedural programming (where functions operate on data), OOD bundles data + methods into classes, enabling modularity and reusability.
1. Classes and Objects: The Building Blocks
- A class is a blueprint (e.g.,
BankAccount), while an object is an instance (e.g.,account123ofSBI_Nepal). - Attributes (data) + methods (functions) define a class’s interface.
- Encapsulation: Hide internal state (e.g.,
private balance) and expose controlled access via methods (deposit(),withdraw()).
classDiagram
class BankAccount {
-accountNumber: String
-balance: Double
+deposit(amount: Double): void
+withdraw(amount: Double): void
+getBalance(): Double
}
class SavingsAccount {
-interestRate: Double
+calculateInterest(): Double
}
BankAccount <|-- SavingsAccountWorked Example: Ncell’s Prepaid Plan
class PrepaidPlan {
private double remainingBalance;
private String customerID;
public void recharge(double amount) {
this.remainingBalance += amount;
}
public boolean makeCall(double duration) {
if (remainingBalance >= duration * 0.50) { // 0.50 NPR/sec
remainingBalance -= duration * 0.50;
return true;
}
return false;
}
}
- Encapsulation:
remainingBalanceis private; users interact only viarecharge()/makeCall(). - Real-world tie: Ncell’s app uses this to track usage and prevent over-charging.
Inheritance: "Is-A" Relationships
Inheritance lets a subclass inherit attributes/methods from a superclass (e.g., ElectricCar inherits from Car). Key terms:
extends: Defines inheritance (e.g.,class ElectricCar extends Car).@Override: Modifies inherited methods (e.g.,calculateTax()).super: Calls parent-class methods.
classDiagram
class Vehicle {
-maxSpeed: Double
+startEngine(): void
}
class Car {
-numDoors: Int
+accelerate(): void
}
class ElectricCar {
-batteryCapacity: Double
+charge(): void
+override accelerate(): void
}
Vehicle <|-- Car
Car <|-- ElectricCarWorked Example: Daraz’s Product Catalog
class Product {
private String id;
private double price;
public double getPrice() { return price; }
}
class ElectronicProduct extends Product {
private double warrantyPeriod;
public double getPriceWithWarranty() {
return super.getPrice() * 1.10; // 10% markup for warranty
}
}
- Why? Daraz groups products hierarchically (e.g.,
ElectronicProductadds warranty logic without duplicatingprice). - Real-world tie: Daraz’s search filters use inheritance to categorize products (e.g.,
Laptop→GamingLaptop).
Polymorphism: "One Interface, Many Forms"
Polymorphism allows objects of different classes to be treated as objects of a common superclass. Two types:
- Compile-time (Method Overloading): Same method name, different parameters.
class Calculator { int add(int a, int b) { return a + b; } double add(double a, double b) { return a + b; } } - Run-time (Method Overriding): Subclass provides specific implementation.
class Shape { double area(); } class Circle extends Shape { double area() { return Math.PI * r * r; } } class Square extends Shape { double area() { return side * side; } }
Visual: Polymorphism in Action
sequenceDiagram
participant UI as User Interface
participant Shape as Shape (abstract)
participant Circle as Circle
participant Square as Square
UI->>Shape: draw()
Shape->>Circle: area() # Runtime decision
Shape->>Square: area()Worked Example: NEPSE’s Stock Trading
interface Stock {
double calculateValue();
}
class EquityStock implements Stock {
public double calculateValue() { return shares * price; }
}
class DerivativeStock implements Stock {
public double calculateValue() { return underlyingValue * multiplier; }
}
- Why? NEPSE’s system processes
EquityStockandDerivativeStockuniformly via theStockinterface. - Real-world tie: When you buy shares on NEPSE’s app, the system calls
calculateValue()polymorphically.
SOLID Principles: The 5 Pillars of Maintainable Code
SOLID principles prevent "spaghetti code" in large systems. Memorize these for exam scenarios!
| Principle | Definition | Example (Bad → Good) |
|---|---|---|
| Single Responsibility | A class should have one reason to change. | ❌ UserManager handles login, profile, and billing. <br> ✅ Split into AuthService, ProfileService, BillingService. |
| Open/Closed | Open for extension, closed for modification. | ❌ Modify Discount class to add new types. <br> ✅ Use Strategy pattern (see below). |
| Liskov Substitution | Subtypes must be substitutable for their base types. | ❌ Square breaks Rectangle if setWidth()/setHeight() are overridden separately. |
| Interface Segregation | Clients shouldn’t depend on interfaces they don’t use. | ❌ Worker interface forces clean() on Manager. <br> ✅ Split into Worker and Manager. |
| Dependency Inversion | Depend on abstractions, not concretions. | ❌ PaymentProcessor directly uses CreditCard. <br> ✅ Inject PaymentMethod interface. |
Worked Example: eSewa’s Payment Gateway
// Violation: Dependency on concrete class
class PaymentProcessor {
private CreditCard card;
public void processPayment(double amount) { ... }
}
// Fix: Dependency Inversion
interface PaymentMethod { void pay(double amount); }
class CreditCard implements PaymentMethod { ... }
class Khalti implements PaymentMethod { ... }
class PaymentProcessor {
private PaymentMethod method;
public void processPayment(double amount) {
method.pay(amount); // Works with any PaymentMethod
}
}
- Why? eSewa supports multiple payment methods (credit card, Khalti, mobile banking) without modifying
PaymentProcessor.
Design Patterns: The "Gang of Four" (GoF) Patterns
Design patterns are proven solutions to common problems. Categorized into 3 groups:
1. Creational Patterns: Object Creation Mechanisms
| Pattern | Purpose | Example |
|---|---|---|
| Singleton | Ensure a class has one instance (e.g., database connection). | Database.getInstance() returns the same Connection object. |
| Factory Method | Delegate instantiation to subclasses. | VehicleFactory.createVehicle("car") returns Car or Truck. |
| Builder | Construct complex objects step-by-step. | PizzaBuilder.setToppings().setSauce().build(). |
Visual: Singleton Pattern
classDiagram
class Database {
-instance: Database
+getInstance(): Database
-Database() { /* private constructor */ }
}Worked Example: NTC’s Network Connection Pool
class NetworkConnection {
private static NetworkConnection instance;
private NetworkConnection() { /* setup */ }
public static synchronized NetworkConnection getInstance() {
if (instance == null) {
instance = new NetworkConnection();
}
return instance;
}
}
- Why? NTC reuses a single connection pool for all users to avoid overhead.
2. Structural Patterns: Class/Object Composition
| Pattern | Purpose | Example |
|---|---|---|
| Adapter | Make incompatible interfaces work together. | LegacyPrinterAdapter lets new apps use old printers. |
| Decorator | Add responsibilities dynamically. | Espresso → MilkDecorator → SugarDecorator. |
| Facade | Simplify complex subsystems. | HomeTheaterFacade hides DVDPlayer, Projector, SoundSystem. |
Visual: Decorator Pattern
classDiagram
class Coffee {
+cost(): Double
}
class Espresso {
+cost(): Double
}
class MilkDecorator {
-coffee: Coffee
+cost(): Double
}
class SugarDecorator {
-coffee: Coffee
+cost(): Double
}
Coffee <|-- Espresso
Coffee <|-- MilkDecorator
Coffee <|-- SugarDecoratorWorked Example: Pathao’s Ride Pricing
interface RideCost {
double calculate();
}
class BaseCost implements RideCost {
public double calculate() { return distance * 10; }
}
class SurgeDecorator implements RideCost {
private RideCost rideCost;
public SurgeDecorator(RideCost rc) { this.rideCost = rc; }
public double calculate() { return rideCost.calculate() * 1.5; } // 50% surge
}
- Why? Pathao adds surge pricing dynamically without modifying
BaseCost.
3. Behavioral Patterns: Object Interaction
| Pattern | Purpose | Example |
|---|---|---|
| Observer | Define 1-to-many dependencies (e.g., publish-subscribe). | TrafficUpdate notifies all RideApps (Pathao, Uber) of delays. |
| Strategy | Encapsulate interchangeable algorithms. | SortingStrategy swaps QuickSort/MergeSort at runtime. |
| Command | Encapsulate actions as objects. | UndoCommand for text editors (like Microsoft Word). |
Visual: Observer Pattern
sequenceDiagram
participant TrafficSystem as TrafficUpdateSystem
participant Pathao as Pathao App
participant Uber as Uber App
TrafficSystem->>Pathao: notify("Delays on Ring Road")
TrafficSystem->>Uber: notify("Delays on Ring Road")Worked Example: Ncell’s Roaming Alerts
interface Observer { void update(String message); }
class RoamingAlertSystem {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer o) { observers.add(o); }
public void sendAlert(String message) {
for (Observer o : observers) {
o.update(message); // Calls Ncell App, SMS Gateway, etc.
}
}
}
- Why? Ncell’s system notifies users via app, SMS, and email without coupling to specific notification methods.
UML Diagrams: Visualizing OO Design
UML (Unified Modeling Language) diagrams bridge theory and implementation. Key diagrams for this unit:
Class Diagram: Shows classes, attributes, methods, and relationships.
- Symbols:
+= public,-= private,#= protected.---= association,---o= aggregation,---⊳= composition.←|= inheritance,⋖= interface.
- Symbols:
Sequence Diagram: Shows object interactions over time (e.g., protocol handshakes).
State Diagram: Models object lifecycle (e.g.,
Orderstates:Placed→Shipped→Delivered).
Worked Example: Daraz Order Processing
stateDiagram-v2
[*] --> Placed
Placed --> Processing: payment confirmed
Processing --> Shipped: inventory reserved
Shipped --> Delivered: dispatched
Delivered --> [*]
Processing --> Cancelled: user request
Shipped --> Cancelled: out of stockRefactoring: Improving Legacy Code with Patterns
Refactoring applies patterns to existing code without changing functionality. Common scenarios:
- Replace Conditional with Strategy: Replace
if-elsechains with polymorphism.// Before if (discountType == "STUDENT") { applyStudentDiscount(); } else if (discountType == "SENIOR") { applySeniorDiscount(); } // After (Strategy Pattern) interface DiscountStrategy { void apply(); } class StudentDiscount implements DiscountStrategy { ... } class SeniorDiscount implements DiscountStrategy { ... } - Introduce Adapter: Wrap legacy code to fit new interfaces.
- Use Flyweight: Share common data (e.g., Daraz’s product images).
In the Real World
eSewa’s Payment Gateway
- Pattern: Strategy (for different payment methods: credit card, Khalti, mobile banking).
- How: The system injects a
PaymentMethodobject (e.g.,KhaltiPayment) at runtime, letting users switch without changing the corePaymentProcessor. - Nepali tie: When you pay utility bills via eSewa, the app dynamically selects the strategy based on your chosen method.
Pathao’s Ride-Matching Algorithm
- Pattern: Observer (for real-time traffic updates) + Singleton (for the central dispatch system).
- How:
- The
TrafficUpdateSystem(Singleton) notifies all ride apps (Observer) of delays. - The dispatch system (Singleton) ensures one instance manages all ride assignments.
- The
- Nepali tie: During Kathmandu traffic jams, Pathao reroutes drivers using these patterns to minimize wait times.
NEPSE’s Stock Trading Platform
- Pattern: Factory Method (for creating different order types) + Command (for undoing trades).
- How:
OrderFactory.createOrder("BUY", "NEPSE:1")returns aBuyOrderorSellOrder.- Traders can undo actions via
UndoCommand, stored in a stack.
- Nepali tie: When you place a trade on NEPSE’s website, the system uses these patterns to handle your order and allow cancellations.
Daraz’s Product Catalog
- Pattern: Composite (for product hierarchies) + Flyweight (for shared product images).
- How:
ElectronicProductinherits fromProductbut addswarrantyPeriod.- Thumbnail images are stored once (Flyweight) and reused across listings.
- Nepali tie: When you browse Daraz, the site loads product images efficiently and categorizes items hierarchically.
Exam Tip
Pattern Identification: Exams often ask:
- "Which GoF pattern would you use for a [scenario]?"
- Example: "Design a system where users can subscribe to live traffic updates." Answer: Observer Pattern (TrafficUpdateSystem notifies subscribers like Pathao/Uber).
- Memorize use cases:
- Need one instance? → Singleton.
- Need dynamic behavior? → Strategy.
- Need event handling? → Observer.
UML Questions: Draw diagrams from descriptions. For example:
- "Show a class diagram for a
Vehiclehierarchy withCarandElectricCar." Must include: Inheritance arrow (<|--), attributes (maxSpeed), and methods (accelerate()).
- "Show a class diagram for a
SOLID Violations: Spot anti-patterns in code snippets. For example:
- "This class handles both user authentication and database logging. Which SOLID principle is violated?" Answer: Single Responsibility Principle (SRP).
Real-World Scenarios: Relate patterns to Nepali apps. For example:
- "How would you implement Khalti’s payment integration in eSewa using design patterns?"
Answer:
- Use Strategy Pattern to switch between
KhaltiPayment,CreditCardPayment, etc. - Use Observer Pattern to notify users of payment status updates.
- Use Strategy Pattern to switch between
- "How would you implement Khalti’s payment integration in eSewa using design patterns?"
Answer:
Code Snippets: Be ready to write short implementations. For example:
- "Implement the Singleton pattern for a
DatabaseConnectionclass."public class DatabaseConnection { private static DatabaseConnection instance; private DatabaseConnection() {} public static DatabaseConnection getInstance() { if (instance == null) { instance = new DatabaseConnection(); } return instance; } }
- "Implement the Singleton pattern for a
Diagram Labels: In UML questions, label every arrow and box. For example:
- Inheritance:
Car <|-- ElectricCar(withElectricCaraboveCar). - Association:
User --- Order(with multiplicity1to*).
- Inheritance:
Pro Tip: Create a cheat sheet with:
- GoF patterns table (creational/structural/behavioral).
- SOLID acronym with one-line definitions.
- UML symbols (e.g.,
---o= aggregation). - Nepali app examples (eSewa = Strategy, Pathao = Observer).
Based on the TU BITM syllabus for Software Design and Development (IT242), unit 6.
Discussion
Loading…