Bird
Raised Fist0
LLDsystem_design~7 mins

Why behavioral patterns define object interaction in LLD - Why This Architecture

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Problem Statement
When objects in a system interact without clear rules, communication becomes chaotic and error-prone. This leads to tightly coupled code that is hard to maintain, extend, or debug because changes in one object ripple unpredictably to others.
Solution
Behavioral patterns establish clear, reusable ways for objects to communicate and collaborate. They define roles and protocols for interaction, reducing dependencies and making the flow of control and data explicit and manageable.
Architecture
┌─────────────┐       ┌─────────────┐       ┌─────────────┐
│   Object A  │──────▶│   Object B  │──────▶│   Object C  │
└─────────────┘       └─────────────┘       └─────────────┘
       │                    ▲                    │
       │                    │                    │
       └────────────────────┴────────────────────┘

This diagram shows how objects interact in a defined sequence, with clear communication paths that behavioral patterns help organize.

Trade-offs
✓ Pros
Improves code maintainability by decoupling object interactions.
Makes communication between objects explicit and easier to understand.
Facilitates reuse of interaction logic across different parts of the system.
Helps manage complex control flows by defining clear protocols.
✗ Cons
Adds some upfront design complexity to define interaction roles and protocols.
May introduce additional layers of abstraction that can be confusing initially.
Improper use can lead to over-engineering for simple interactions.
Use when multiple objects need to collaborate with clear, reusable communication patterns, especially in systems with complex workflows or frequent changes in interaction logic.
Avoid when object interactions are very simple or unlikely to change, as the added abstraction may complicate the design unnecessarily.
Real World Examples
Amazon
Uses the Observer pattern to notify multiple services about order status changes, ensuring decoupled and scalable event handling.
Netflix
Applies the Strategy pattern to switch between different recommendation algorithms dynamically based on user context.
Uber
Employs the Command pattern to queue and execute ride requests asynchronously, managing complex workflows reliably.
Code Example
The before code tightly couples Switch to Light, making it hard to add more devices. The after code uses the Observer pattern to let Switch notify any number of observers, improving flexibility and reducing coupling.
LLD
### Before: Objects interact directly with tight coupling
class Light:
    def turn_on(self):
        print("Light turned on")

class Switch:
    def __init__(self, light):
        self.light = light
    def press(self):
        self.light.turn_on()

light = Light()
switch = Switch(light)
switch.press()

### After: Using Observer pattern to decouple interaction
class Light:
    def turn_on(self):
        print("Light turned on")

class Switch:
    def __init__(self):
        self._observers = []
    def register(self, observer):
        self._observers.append(observer)
    def press(self):
        for observer in self._observers:
            observer.turn_on()

light = Light()
switch = Switch()
switch.register(light)
switch.press()
OutputSuccess
Alternatives
Structural patterns
Focus on object composition and relationships rather than communication behavior.
Use when: Choose when the problem is about organizing classes and objects rather than their interaction.
Creational patterns
Focus on object creation mechanisms instead of how objects interact.
Use when: Choose when the main challenge is how to instantiate objects flexibly.
Summary
Behavioral patterns prevent chaotic and tightly coupled object interactions by defining clear communication protocols.
They improve code maintainability and flexibility by decoupling objects and making interactions explicit.
Using behavioral patterns helps manage complex workflows and reuse interaction logic effectively.

Practice

(1/5)
1. What is the main purpose of behavioral design patterns in object-oriented design?
easy
A. To specify the structure of classes and objects
B. To define how objects interact and communicate with each other
C. To manage memory allocation for objects
D. To handle database connections efficiently

Solution

  1. Step 1: Understand behavioral patterns' role

    Behavioral patterns focus on the interaction and communication between objects rather than their structure.
  2. Step 2: Differentiate from other pattern types

    Structural patterns define class and object composition, while creational patterns handle object creation. Behavioral patterns organize object collaboration.
  3. Final Answer:

    To define how objects interact and communicate with each other -> Option B
  4. Quick Check:

    Behavioral patterns = object interaction [OK]
Hint: Behavioral = how objects talk and work together [OK]
Common Mistakes:
  • Confusing behavioral with structural patterns
  • Thinking behavioral patterns manage memory
  • Assuming behavioral patterns handle object creation
2. Which of the following is a correct example of a behavioral pattern syntax in a class diagram?
easy
A. Class A uses Class B to perform an action
B. Class A inherits from Class B
C. Class A contains Class B as a member variable
D. Class A creates an instance of Class B

Solution

  1. Step 1: Identify behavioral pattern syntax

    Behavioral patterns show how classes interact, such as one class using another to perform actions.
  2. Step 2: Differentiate from other relationships

    Inheritance, composition, and object creation relate to structural or creational patterns, not behavioral interaction.
  3. Final Answer:

    Class A uses Class B to perform an action -> Option A
  4. Quick Check:

    Behavioral pattern = usage interaction [OK]
Hint: Behavioral means 'uses' or 'communicates with' in diagrams [OK]
Common Mistakes:
  • Confusing inheritance with interaction
  • Mixing composition with behavioral usage
  • Thinking object creation is behavioral interaction
3. Consider the following code snippet implementing the Observer pattern:
class Subject:
    def __init__(self):
        self.observers = []
    def register(self, observer):
        self.observers.append(observer)
    def notify(self, message):
        for obs in self.observers:
            obs.update(message)

class Observer:
    def update(self, message):
        print(f"Received: {message}")

subject = Subject()
obs1 = Observer()
obs2 = Observer()
subject.register(obs1)
subject.register(obs2)
subject.notify("Hello")
What will be the output when subject.notify("Hello") is called?
medium
A. Received: Hello Received: Hello
B. Hello
C. No output
D. Error: update method not found

Solution

  1. Step 1: Understand Observer pattern flow

    The Subject keeps a list of observers and calls their update method with the message when notify is called.
  2. Step 2: Trace notify call

    Calling notify("Hello") loops over obs1 and obs2, calling update("Hello") on each, which prints "Received: Hello" twice.
  3. Final Answer:

    Received: Hello Received: Hello -> Option A
  4. Quick Check:

    Observer update called twice = two prints [OK]
Hint: Observer calls update on all registered objects [OK]
Common Mistakes:
  • Assuming only one observer is notified
  • Expecting notify to print directly
  • Forgetting observers must implement update
4. In the following code snippet implementing the Chain of Responsibility pattern, what is the error?
class Handler:
    def __init__(self, successor=None):
        self.successor = successor
    def handle(self, request):
        if self.can_handle(request):
            print(f"Handled {request}")
        else:
            self.successor.handle(request)
    def can_handle(self, request):
        return False

h1 = Handler()
h2 = Handler(h1)
h2.handle("Request")
medium
A. handle method does not print anything
B. can_handle method is missing
C. Successor is assigned incorrectly
D. Calling handle on None successor causes error

Solution

  1. Step 1: Analyze successor chain

    h2's successor is h1, h1's successor is None by default.
  2. Step 2: Trace handle calls

    Neither handler can handle the request, so h2 calls h1.handle, then h1 calls self.successor.handle which is None.handle causing an error.
  3. Final Answer:

    Calling handle on None successor causes error -> Option D
  4. Quick Check:

    None successor leads to AttributeError [OK]
Hint: Check if successor is None before calling handle [OK]
Common Mistakes:
  • Ignoring None successor causing crash
  • Assuming can_handle is missing
  • Thinking print is missing output
5. You are designing a messaging system where multiple objects need to react to events from a central source without tight coupling. Which behavioral pattern best fits this requirement and why?
hard
A. Decorator pattern, because it adds responsibilities to message objects
B. Singleton pattern, because it ensures only one instance handles all messages
C. Observer pattern, because it allows objects to subscribe and get notified of changes
D. Factory pattern, because it creates message objects dynamically

Solution

  1. Step 1: Identify the need for loose coupling and event notification

    The system requires multiple objects to react to events without tight connections, which means they should be able to subscribe and be notified.
  2. Step 2: Match pattern to requirement

    The Observer pattern fits perfectly as it allows objects to register as observers and get notified when the subject changes, promoting loose coupling.
  3. Final Answer:

    Observer pattern, because it allows objects to subscribe and get notified of changes -> Option C
  4. Quick Check:

    Loose coupling + notifications = Observer [OK]
Hint: Observer = subscribe and notify for loose coupling [OK]
Common Mistakes:
  • Choosing Singleton which limits to one instance
  • Confusing creation patterns with interaction patterns
  • Using Decorator which adds features, not notifications