Bird
Raised Fist0
LLDsystem_design~7 mins

Why structural patterns organize class relationships in LLD - Why This Architecture

Choose your learning style10 modes available
Problem Statement
When classes in a software system are tightly coupled or poorly organized, changes in one class can cause unexpected issues in others. This leads to fragile code that is hard to maintain, extend, or reuse, increasing the risk of bugs and slowing down development.
Solution
Structural patterns solve this by defining clear ways to organize classes and their relationships. They create flexible connections between classes, allowing them to work together without being tightly bound. This makes the system easier to change and extend without breaking existing code.
Architecture
Client
→Interface
↓
Adapter

This diagram shows how structural patterns like Adapter and Decorator organize class relationships by introducing interfaces and wrapper classes between the client and concrete implementations.

Trade-offs
✓ Pros
→
Reduces tight coupling between classes, improving maintainability.
→
Enables easier extension of functionality without modifying existing code.
→
Promotes code reuse by composing behaviors from smaller classes.
→
Improves flexibility in how classes interact and collaborate.
✗ Cons
→
Can introduce additional layers of abstraction, making the design more complex.
→
May increase the number of classes, which can be harder to navigate for beginners.
→
Sometimes performance overhead due to extra indirection.
Use when your system has complex class relationships that need to be flexible and maintainable, especially if you expect frequent changes or extensions in behavior.
Avoid when the system is very simple with few classes and relationships, as the added abstraction may complicate the design unnecessarily.
Real World Examples
Netflix
Uses the Decorator pattern to add features like caching and logging to streaming components without changing their core logic.
Amazon
Applies the Adapter pattern to integrate different payment gateways with a unified interface, allowing easy addition of new payment methods.
LinkedIn
Employs the Composite pattern to represent complex organizational hierarchies where groups and individuals are treated uniformly.
Code Example
The before code shows a Car class tightly coupled to a specific Engine class, making it hard to replace the engine. The after code introduces an Adapter that wraps an OldEngine with a start() method, allowing Car to use any engine with a start() method. This organizes class relationships to reduce coupling and increase flexibility.
LLD
### Before: Tight coupling without structural pattern
class Engine:
    def start(self):
        print("Engine started")

class Car:
    def __init__(self):
        self.engine = Engine()  # Direct dependency
    def drive(self):
        self.engine.start()
        print("Car is driving")

car = Car()
car.drive()


### After: Using Adapter pattern to decouple
class OldEngine:
    def ignite(self):
        print("Old engine ignited")

class EngineAdapter:
    def __init__(self, old_engine):
        self.old_engine = old_engine
    def start(self):
        self.old_engine.ignite()  # Adapting interface

class Car:
    def __init__(self, engine):
        self.engine = engine
    def drive(self):
        self.engine.start()
        print("Car is driving")

old_engine = OldEngine()
adapted_engine = EngineAdapter(old_engine)
car = Car(adapted_engine)
car.drive()
OutputSuccess
Alternatives
Behavioral patterns
Focus on communication and responsibility between objects rather than their structure.
Use when: Choose when the main challenge is how objects interact or change behavior over time.
Creational patterns
Focus on object creation mechanisms rather than organizing existing classes.
Use when: Choose when object instantiation needs to be controlled or simplified.
Summary
Structural patterns organize class relationships to reduce tight coupling and improve flexibility.
They introduce interfaces and wrapper classes to allow easier extension and maintenance.
These patterns are essential when systems grow complex and need to adapt to change.

Practice

(1/5)
1. What is the main purpose of structural design patterns in organizing class relationships?
easy
A. To simplify system design by organizing how classes relate
B. To improve the speed of the program execution
C. To handle user input and output operations
D. To store data persistently in databases

Solution

  1. Step 1: Understand the role of structural patterns

    Structural patterns focus on how classes and objects are composed to form larger structures.
  2. Step 2: Identify the main goal

    The main goal is to simplify the design by making relationships flexible and clear.
  3. Final Answer:

    To simplify system design by organizing how classes relate -> Option A
  4. Quick Check:

    Structural patterns simplify class relationships [OK]
Hint: Structural patterns simplify class connections [OK]
Common Mistakes:
  • Confusing structural patterns with performance optimization
  • Thinking structural patterns manage data storage
  • Mixing structural patterns with user interface handling
2. Which of the following is a correct example of a structural pattern that organizes class relationships?
easy
A. Factory pattern
B. Singleton pattern
C. Adapter pattern
D. Observer pattern

Solution

  1. Step 1: Recall common structural patterns

    Adapter, Decorator, and Composite are examples of structural patterns.
  2. Step 2: Match options to pattern types

    Adapter is a structural pattern; Singleton is creational; Observer is behavioral; Factory is creational.
  3. Final Answer:

    Adapter pattern -> Option C
  4. Quick Check:

    Adapter = Structural pattern [OK]
Hint: Adapter is a classic structural pattern [OK]
Common Mistakes:
  • Confusing creational patterns with structural ones
  • Selecting Observer which is behavioral
  • Choosing Factory which is creational
3. Given the following class structure using the Decorator pattern, what is the main benefit of this design?
class Coffee {
  cost() { return 5; }
}
class MilkDecorator {
  constructor(coffee) { this.coffee = coffee; }
  cost() { return this.coffee.cost() + 2; }
}
medium
A. It speeds up the cost calculation by caching results
B. It allows adding features dynamically without changing original classes
C. It restricts the coffee class from being extended
D. It stores coffee objects in a database

Solution

  1. Step 1: Analyze the Decorator pattern usage

    The MilkDecorator wraps a Coffee object and adds extra cost dynamically.
  2. Step 2: Understand the benefit

    This design allows adding new features (like milk) without modifying the original Coffee class.
  3. Final Answer:

    It allows adding features dynamically without changing original classes -> Option B
  4. Quick Check:

    Decorator adds features dynamically [OK]
Hint: Decorator adds features without changing original class [OK]
Common Mistakes:
  • Thinking it caches results for speed
  • Believing it restricts class extension
  • Assuming it handles data storage
4. Identify the error in this Adapter pattern implementation:
class OldSystem {
  oldRequest() { return 'Old response'; }
}
class Adapter {
  constructor(oldSystem) { this.oldSystem = oldSystem; }
  request() { return this.oldSystem.request(); }
}
medium
A. Adapter should inherit from OldSystem
B. OldSystem class should not have any methods
C. Constructor is missing in OldSystem
D. Adapter calls a non-existent method 'request' instead of 'oldRequest'

Solution

  1. Step 1: Check method calls in Adapter

    Adapter calls this.oldSystem.request(), but OldSystem has only oldRequest() method.
  2. Step 2: Identify the mismatch

    The Adapter should call oldRequest() to adapt it to request().
  3. Final Answer:

    Adapter calls a non-existent method 'request' instead of 'oldRequest' -> Option D
  4. Quick Check:

    Method name mismatch in Adapter [OK]
Hint: Check method names carefully in Adapter calls [OK]
Common Mistakes:
  • Assuming inheritance is required in Adapter
  • Thinking OldSystem should be empty
  • Ignoring method name differences
5. You need to design a system where multiple objects form a tree structure and clients treat individual objects and compositions uniformly. Which structural pattern best organizes this relationship?
hard
A. Composite pattern
B. Facade pattern
C. Proxy pattern
D. Bridge pattern

Solution

  1. Step 1: Understand the problem requirements

    The system needs to treat individual objects and groups (tree structure) uniformly.
  2. Step 2: Match with structural patterns

    The Composite pattern allows composing objects into tree structures and clients treat them the same.
  3. Step 3: Eliminate other options

    Facade simplifies interfaces, Proxy controls access, Bridge separates abstraction from implementation; none fit the tree structure need.
  4. Final Answer:

    Composite pattern -> Option A
  5. Quick Check:

    Tree structure uniform treatment = Composite [OK]
Hint: Composite handles tree structures uniformly [OK]
Common Mistakes:
  • Confusing Facade with Composite
  • Choosing Proxy for access control only
  • Mixing Bridge with structural composition
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard