IT242 Software Design and Development

Software Design and DevelopmentUnit 616 min read

Object-Oriented Design & Design Patterns: Classes, Inheritance, Polymorphism, SOLID, Gang of Four Patterns

Unit 6 of Software Design and Development explores core object-oriented principles (encapsulation, inheritance, polymorphism, abstraction) and the Gang of Four design patterns (Singleton, Factory, Observer, Strategy, etc.), with real-world applications in Nepalese apps like eSewa and global systems like YouTube.

TAKEAWAYS:

  • Object-oriented design (OOD) organizes software into reusable classes with attributes and methods, mimicking real-world entities (e.g., a BankAccount class with balance and deposit()).
  • The four pillars of OOD—encapsulation, inheritance, polymorphism, and abstraction—reduce redundancy and improve maintainability in large systems like Ncell’s billing software.
  • Design patterns (e.g., Singleton for DatabaseConnection, Factory for PaymentGateway) solve recurring problems without reinventing the wheel in apps like Khalti or Pathao.
  • SOLID principles (Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion) prevent "spaghetti code" in legacy systems like NTC’s network management tools.
  • UML diagrams (class diagrams, sequence diagrams) visually model interactions between objects, critical for designing eSewa’s transaction flow.
  • Patterns like Observer (used in YouTube’s subscriber notifications) and Strategy (used in Daraz’s shipping algorithms) optimize performance and scalability.

1. Object-Oriented Design (OOD) Fundamentals

OOD is a paradigm that models software as a collection of objects (instances of classes) that interact with each other. Unlike procedural programming (where logic is split into functions), OOD groups data (attributes) and behavior (methods) into cohesive units.

Key Concepts

classDiagram
    class Class {
        +attributes
        +methods()
    }
    class Object {
        -state
        +behavior()
    }
    Class <|-- Object : "is-a"
    Class --> Object : "creates"
  • Class: A blueprint (e.g., Customer, Order). Defines attributes (e.g., customerId: String) and methods (e.g., placeOrder()).
  • Object: An instance of a class (e.g., customer1 of type Customer).
  • Encapsulation: Bundling data and methods that operate on the data, while restricting direct access (using getters/setters or private fields). Example: A BankAccount class hides balance but exposes withdraw(amount) to prevent invalid operations.
  • Inheritance: A mechanism where a subclass (child) inherits properties/methods from a superclass (parent). Example: SavingsAccount inherits from BankAccount but adds calculateInterest().
  • Polymorphism: "Many forms"—objects of different classes can be treated as objects of a common superclass. Example: A PaymentProcessor can accept CreditCard, Khalti, or Esewa objects via a common processPayment() method.
  • Abstraction: Hiding complex implementation details and exposing only essential features (e.g., interfaces or abstract classes). Example: An Animal abstract class defines makeSound() but lets Dog and Cat implement it differently.

Worked Example: eSewa Transaction System

classDiagram
    class Transaction {
        <<abstract>>
        +amount: Double
        +process()
    }
    class EsewaTransaction {
        +fee: Double
        +process()
    }
    class KhaltiTransaction {
        +process()
    }
    Transaction <|-- EsewaTransaction
    Transaction <|-- KhaltiTransaction
    class User {
        +placeTransaction(paymentType: Transaction)
    }
    User --> Transaction : "uses"
  • Problem: eSewa wants to support multiple payment gateways (Esewa, Khalti, Ncell) without duplicating transaction logic.
  • Solution:
    • Define an abstract Transaction class with process().
    • Create subclasses (EsewaTransaction, KhaltiTransaction) overriding process().
    • The User class calls placeTransaction() without knowing the concrete type (polymorphism).

2. SOLID Principles: Writing Maintainable Code

SOLID is an acronym for 5 principles that improve code design and reduce technical debt. Violating these leads to "spaghetti code" (hard to maintain, e.g., NTC’s old billing system).

Principle Violation Example Fix
Single Responsibility A User class handles login, profile, and orders. Split into UserAuth, UserProfile, OrderManager.
Open/Closed Discount class is modified for new rules. Extend with SummerDiscount, BlackFridayDiscount (inheritance).
Liskov Substitution A Square breaks Rectangle’s behavior. Ensure subclasses honor superclass contracts (e.g., area calculation).
Interface Segregation A Worker interface forces unrelated methods. Split into Workable, Payable.
Dependency Inversion High-level OrderSystem depends on low-level Database. Depend on abstractions (IDatabase) instead of concrete classes.

Real-World Tie-In: Ncell Billing System

  • Problem: The old system had a monolithic Billing class handling calls, SMS, and internet—violating SRP.
  • Fix: Refactored into:
    • CallBilling (handles call charges)
    • SMSBilling (handles SMS)
    • InternetBilling (handles data usage)
    • Customer (aggregates all billing types via composition).

3. Design Patterns: Reusable Solutions

Design patterns are proven templates for solving common problems in software design. The Gang of Four (GoF) cataloged 23 patterns, grouped into 3 categories:

mindmap
  root((Design Patterns))
    Creational
      Singleton["Singleton: One instance (e.g., `DatabaseConnection`)"]
      Factory["Factory: Create objects without specifying class (e.g., `PaymentGatewayFactory`)"]
      AbstractFactory["AbstractFactory: Families of related objects (e.g., UI components)"]
    Structural
      Adapter["Adapter: Bridge incompatible interfaces (e.g., legacy `NTCModem`)"]
      Decorator["Decorator: Add responsibilities dynamically (e.g., `EncryptedOrder`)"]
      Facade["Facade: Simplify complex subsystems (e.g., `OrderProcessingFacade`)"]
    Behavioral
      Observer["Observer: Event handling (e.g., `YouTube` notifications)"]
      Strategy["Strategy: Swap algorithms (e.g., `Daraz` shipping methods)"]
      Command["Command: Encapsulate requests (e.g., `Undo/Redo` in apps)"]

Key Patterns in Nepalese Apps

Pattern Example in Nepal How It Works
Singleton DatabaseConnection in eSewa Ensures only one connection pool exists to avoid resource leaks.
Factory PaymentGatewayFactory in Khalti Creates EsewaGateway, KhaltiGateway, or CreditCardGateway dynamically.
Observer YouTube/Pathao notifications Subscribers (Observer) are notified when a new order (Subject) is placed.
Strategy Daraz shipping algorithms Swaps StandardDelivery, ExpressDelivery, or SameDayDelivery strategies.
Decorator Adding taxes to an order in Daraz Wraps Order with TaxDecorator, DiscountDecorator without modifying core.

Worked Example: Pathao Driver Assignment (Strategy Pattern)

classDiagram
    class DriverAssignment {
        +assignDriver(strategy: AssignmentStrategy)
    }
    class AssignmentStrategy {
        <<interface>>
        +assign()
    }
    class DistanceBasedStrategy {
        +assign()
    }
    class AvailabilityBasedStrategy {
        +assign()
    }
    AssignmentStrategy <|-- DistanceBasedStrategy
    AssignmentStrategy <|-- AvailabilityBasedStrategy
    DriverAssignment --> AssignmentStrategy : "uses"
  • Problem: Pathao needs to assign drivers based on either closest distance or driver availability.
  • Solution:
    • Define AssignmentStrategy interface with assign().
    • Implement DistanceBasedStrategy (picks nearest driver) and AvailabilityBasedStrategy (picks available driver).
    • DriverAssignment class swaps strategies at runtime (e.g., switch to AvailabilityBasedStrategy during peak hours).

4. UML Diagrams for OOD

UML (Unified Modeling Language) provides visual tools to model OOD. For this unit, focus on:

  1. Class Diagrams: Show classes, attributes, methods, and relationships.
  2. Sequence Diagrams: Model interactions between objects over time.

Example: Khalti Payment Flow (Sequence Diagram)

sequenceDiagram
    participant User
    participant KhaltiApp
    participant KhaltiServer
    participant Bank
    User->>KhaltiApp: Select "Pay with Khalti"
    KhaltiApp->>KhaltiServer: Request payment (amount, orderId)
    KhaltiServer->>Bank: Debit account
    Bank-->>KhaltiServer: Confirmation
    KhaltiServer-->>KhaltiApp: Success
    KhaltiApp-->>User: Show "Payment successful"
  • Key Interactions:
    1. User triggers payment in the app.
    2. KhaltiApp acts as a Facade, hiding complexity from the user.
    3. KhaltiServer uses the Strategy pattern to route to the correct bank.
    4. Observer pattern could notify the merchant (e.g., Daraz) of the payment status.

Class Diagram: NEPSE Stock Trading System

classDiagram
    class User {
        +userId: String
        +placeOrder(order: Order)
    }
    class Order {
        +orderId: String
        +stockSymbol: String
        +quantity: int
        +execute()
    }
    class MarketOrder {
        +execute()
    }
    class LimitOrder {
        +price: Double
        +execute()
    }
    class StockExchange {
        +process(order: Order)
    }
    Order <|-- MarketOrder
    Order <|-- LimitOrder
    User --> Order : "places"
    Order --> StockExchange : "sends to"
  • Key Design Choices:
    • Polymorphism: MarketOrder and LimitOrder override execute().
    • Dependency Inversion: User depends on Order (abstraction), not concrete implementations.
    • Open/Closed: New order types (e.g., StopLossOrder) can be added without modifying User.

5. Common Pitfalls and Anti-Patterns

Anti-Pattern Description Fix
God Object A single class does everything (e.g., SuperUser handling all logic). Split into smaller classes (SRP).
Circular Dependency Class A depends on Class B, which depends on Class A. Use Dependency Injection or refactor into a mediator.
Overuse of Inheritance Deep inheritance hierarchies (e.g., 10 levels for Vehicle). Prefer composition (e.g., Car has-a Engine).
Tight Coupling Classes are tightly linked (e.g., Order knows about Database). Introduce interfaces (Dependency Inversion).
Premature Optimization Adding patterns (e.g., Singleton) where not needed. Follow YAGNI (You Aren’t Gonna Need It).

Real-World Example: Kathmandu Traffic Routes

  • Anti-Pattern: Early GPS systems in Kathmandu used a monolithic route-finding algorithm (tight coupling).
  • Fix: Modern apps like Pathao use:
    • Strategy Pattern: Swap between FastestRoute, ShortestRoute, or AvoidTolls.
    • Observer Pattern: Real-time traffic updates notify drivers of delays.

## In the Real World

  1. eSewa (Nepal)

    • Patterns Used: Singleton (for DatabaseConnection), Factory (for PaymentGateway), Observer (for transaction notifications).
    • How It Works:
      • Only one DatabaseConnection instance exists (Singleton) to avoid connection leaks.
      • The PaymentProcessor uses a Factory to create EsewaGateway or CreditCardGateway dynamically.
      • Merchants (e.g., Daraz) are notified via Observer when a payment is confirmed.
  2. Khalti (Nepal)

    • Patterns Used: Strategy (for different payment methods), Decorator (for adding fees/taxes).
    • How It Works:
      • At checkout, Khalti swaps the PaymentStrategy based on user choice (credit card, mobile wallet, bank transfer).
      • A TaxDecorator wraps the order to add VAT dynamically without modifying the core Order class.
  3. YouTube (Global)

    • Patterns Used: Observer (for subscriber notifications), Proxy (for lazy-loading video thumbnails).
    • How It Works:
      • When you subscribe to a channel, YouTube registers your account as an Observer to the channel’s Subject.
      • When the channel uploads a video, all observers (subscribers) are notified via the Observer pattern.
  4. Daraz (Nepal)

    • Patterns Used: Command (for order history/undo), State (for order status: "Processing," "Shipped," "Delivered").
    • How It Works:
      • The Order class uses the State pattern to transition between states (e.g., ProcessingState, ShippedState).
      • The Command pattern stores order actions (e.g., "Cancel Order") in a stack for undo functionality.
  5. NTC Network Management

    • Patterns Used: Facade (simplifies complex network operations), Singleton (for NetworkConfig).
    • How It Works:
      • The NetworkFacade provides methods like restartRouter() without exposing low-level details.
      • Only one NetworkConfig instance exists to ensure consistent settings across the network.

## Exam Tip

This unit is heavily tested in TU/PU exams through:

  1. Diagram Questions (30%):

    • Draw class diagrams for given scenarios (e.g., "Design a Library system with Book, Member, and Loan classes").
    • Draw sequence diagrams for workflows (e.g., "Show the interaction between a user and Khalti during payment").
    • Common Mistakes:
      • Forgetting to show inheritance arrows (<|--) or associations (-->).
      • Missing visibility modifiers (+, -, #) in UML.
  2. Code-Based Questions (40%):

    • Identify patterns in given code snippets (e.g., "Which GoF pattern is used here?"). Example:
      public class PaymentProcessor {
          private PaymentStrategy strategy;
          public void setStrategy(PaymentStrategy strategy) {
              this.strategy = strategy;
          }
          public void process() {
              strategy.pay();
          }
      }
      
      Answer: Strategy Pattern (swaps CreditCardStrategy, KhaltiStrategy).
    • Refactor code to follow SOLID principles (e.g., "Violate SRP in this User class").
    • Implement patterns from scratch (e.g., "Write a Singleton class for DatabaseConnection").
  3. Scenario-Based Questions (30%):

    • Apply patterns to real-world problems (e.g., "How would you design Pathao’s driver assignment system?"). Expected Answer:
      • Use Strategy Pattern for DistanceBasedStrategy and AvailabilityBasedStrategy.
      • Use Observer Pattern to notify drivers of new orders.
    • Explain trade-offs (e.g., "When would you use Inheritance vs. Composition?"). Answer:
      Criteria Inheritance Composition
      Flexibility Low (hard to change hierarchy) High (dynamic composition)
      Code Reuse High (shared methods) Low (delegation needed)
      Example in Nepal SavingsAccount extends Account Car has-a Engine
  4. Short-Answer Questions:

    • Define terms: "What is polymorphism?", "Explain the Open/Closed Principle."
    • Common Exam Phrases:
      • "Differentiate between composition and inheritance."
      • "Give an example of the Decorator pattern in a Nepalese app."
      • "How does the Observer pattern improve scalability in YouTube?"

Pro Tip for Full Marks:

  • Always draw diagrams for design questions—even if not explicitly asked.
  • Relate answers to Nepalese apps (e.g., eSewa, Khalti, Daraz) to show practical understanding.
  • Use SOLID as a checklist when evaluating code designs (e.g., "This violates SRP because...").
  • Memorize the GoF patterns by category (Creational/Structural/Behavioral) and one real-world example each.

Based on the TU BIM syllabus for Software Design and Development (IT242), unit 6.

Discussion

Loading…