Bird
Raised Fist0
Interview Prepoop-design-patternsmediumAmazonGoogleMicrosoftFlipkartRazorpaySwiggyZepto

Interface Segregation & Dependency Inversion - Fat Interfaces & IoC

Choose your preparation mode3 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
Steps
setup

Identify Fat Interface

We start with a single fat interface 'IMultiFunctionDevice' that declares multiple unrelated methods for printing, scanning, and faxing.

💡 Recognizing a fat interface is the first step to applying Interface Segregation Principle (ISP).
Line:interface IMultiFunctionDevice { void print(Document d); void scan(Document d); void fax(Document d); }
💡 Fat interfaces bundle unrelated responsibilities, causing clients to depend on methods they don't use.
📊
Interface Segregation & Dependency Inversion - Fat Interfaces & IoC - Watch the Algorithm Execute, Step by Step
Watching this step-by-step visualization helps you understand how SOLID principles improve design by reducing coupling and increasing flexibility, which is hard to grasp from code alone.
Step 1/10
·Active fillAnswer cell
Shows a fat interface violating Interface Segregation Principle.
«interface»IMultiFunctionDevice
+print()
+scan()
+fax()
Clients depending on IMultiFunctionDevice must implement all methods, even if unused.
Demonstrates Interface Segregation Principle by splitting responsibilities.
«interface»IPrinter
+print()
«interface»IScanner
+scan()
«interface»IFax
+fax()
Shows class implementing a segregated interface.
«interface»IPrinter
+print()
Printer
+print()
Printer IPrinter (1:1)
Another example of ISP applied to class design.
«interface»IScanner
+scan()
Scanner
+scan()
Scanner IScanner (1:1)
Demonstrates Dependency Inversion and IoC by depending on interfaces and composing implementations.
«interface»IPrinter
+print()
«interface»IScanner
+scan()
MultiFunctionMachine
printer: IPrinter
scanner: IScanner
+print()
+scan()
MultiFunctionMachine IPrinter (1:1)MultiFunctionMachine IScanner (1:1)MultiFunctionMachine IPrinter (1:1)MultiFunctionMachine IScanner (1:1)
Constructor injection enables inversion of control.
MultiFunctionMachine
printer: IPrinter
scanner: IScanner
+MultiFunctionMachine()
+print()
+scan()
MultiFunctionMachine IPrinter (1:1)MultiFunctionMachine IScanner (1:1)
Delegation pattern used to forward calls.
MultiFunctionMachine
printer: IPrinter
scanner: IScanner
+print()
+scan()
Delegation pattern continued.
MultiFunctionMachine
printer: IPrinter
scanner: IScanner
+print()
+scan()
Dependency Inversion Principle illustrated by depending on interfaces.
«interface»IPrinter
«interface»IScanner
Printer
Scanner
MultiFunctionMachine
printer: IPrinter
scanner: IScanner
Printer IPrinter (1:1)Scanner IScanner (1:1)MultiFunctionMachine IPrinter (1:1)MultiFunctionMachine IScanner (1:1)
Final design combining ISP and DIP with IoC.
«interface»IPrinter
«interface»IScanner
«interface»IFax
Printer
Scanner
Fax
MultiFunctionMachine
printer: IPrinter
scanner: IScanner
fax: IFax
Printer IPrinter (1:1)Scanner IScanner (1:1)Fax IFax (1:1)MultiFunctionMachine IPrinter (1:1)MultiFunctionMachine IScanner (1:1)MultiFunctionMachine IFax (1:1)

Key Takeaways

Fat interfaces force clients to depend on methods they don't use, violating Interface Segregation Principle.

This is hard to see from code alone because the problem is conceptual and relates to coupling, not syntax.

Splitting interfaces into smaller, focused ones allows classes to implement only what they need, improving modularity.

Visualizing the interfaces and implementations side-by-side clarifies how responsibilities are separated.

Dependency Inversion Principle and Inversion of Control decouple high-level modules from low-level modules by depending on abstractions and injecting dependencies.

Seeing the relationships and constructor injection visually makes the abstract DIP concept concrete.

Practice

(1/5)
1. In designing a parking lot system using OOP, which component is best suited to decide which type of parking spot (e.g., compact, large, handicapped) should be allocated to an incoming vehicle?
easy
A. The ParkingLot class, as it manages all spots and vehicles
B. The ParkingSpot class, since it represents the spot's characteristics
C. The Vehicle class, because it knows its own size and type
D. A Factory or Strategy pattern component that encapsulates the allocation logic

Solution

  1. Step 1: Understand responsibilities

    The Vehicle class only knows about itself, not allocation rules. The ParkingSpot class represents a spot but doesn't decide allocation. The ParkingLot manages overall state but delegating allocation logic to a dedicated component improves modularity.
  2. Step 2: Recognize design pattern role

    The Factory or Strategy pattern encapsulates allocation logic, allowing easy extension and modification without changing core classes.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Allocation logic centralized -> easier to maintain and extend [OK]
Hint: Allocation logic belongs in a dedicated pattern component, not core entities [OK]
Common Mistakes:
  • Assigning allocation responsibility to Vehicle or ParkingSpot classes
  • Putting all logic inside ParkingLot class leading to tight coupling
2. You have a payment processing system that currently uses multiple if-else statements to handle different payment methods like credit card, UPI, and net banking. The system needs to be extended frequently with new payment methods without modifying existing code. Which design approach best addresses this requirement?
easy
A. Use a brute force approach with nested if-else statements for each payment method.
B. Implement a strategy pattern where each payment method is encapsulated in its own class implementing a common interface.
C. Use a recursive function that selects payment methods based on input parameters.
D. Apply a greedy algorithm to select the payment method with the lowest processing fee.

Solution

  1. Step 1: Understand the problem of frequent extension

    The system requires adding new payment methods without modifying existing code, which violates the open-closed principle if using if-else chains.
  2. Step 2: Identify the design pattern that encapsulates behaviors

    The strategy pattern encapsulates each payment method in its own class implementing a common interface, allowing easy extension by adding new classes without changing existing code.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Strategy pattern replaces conditionals with polymorphism [OK]
Hint: Replacing conditionals with polymorphism enables easy extension [OK]
Common Mistakes:
  • Thinking recursion or greedy algorithms solve extensibility here
3. Which of the following is a common trade-off when using a Facade pattern in a large system?
medium
A. Facade can hide too much complexity, making it hard to access advanced features of subsystems
B. Facade increases coupling between client and subsystems by exposing detailed interfaces
C. Facade always adds significant runtime overhead due to extra method calls
D. Facade requires changing the underlying subsystem interfaces to work properly

Solution

  1. Step 1: Recall Facade's purpose

    Facade simplifies complex subsystems by providing a unified interface.
  2. Step 2: Analyze trade-offs

    While Facade simplifies usage, it can hide advanced features, limiting flexibility.
  3. Step 3: Evaluate other options

    A is incorrect because Facade reduces coupling by hiding subsystem details. C is incorrect; Facade's overhead is minimal. D is wrong; Facade does not require changing subsystems.
  4. Final Answer:

    Option A -> Option A
Hint: Facade hides complexity but may hide power
Common Mistakes:
  • Believing Facade increases coupling instead of reducing it
  • Assuming Facade adds heavy runtime overhead
  • Thinking Facade requires modifying subsystems
4. Which of the following statements about the Open/Closed Principle is INCORRECT?
medium
A. OCP means you should never modify existing code once it's written
B. OCP encourages designing modules that can be extended without changing their source code
C. Abstraction and polymorphism are key enablers of OCP
D. OCP helps reduce bugs by minimizing changes to tested code

Solution

  1. Step 1: Analyze statement A

    OCP does not forbid all modifications; it encourages minimizing changes to stable, tested code but allows modifications when necessary.
  2. Step 2: Validate other statements

    Statements B, C, and D correctly describe OCP's goals and mechanisms.
  3. Step 3: Why A is incorrect

    Absolute prohibition of modification is impractical; OCP is about minimizing and isolating changes.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    OCP is about minimizing, not forbidding, modifications.
Hint: OCP minimizes, but does not forbid, code changes [OK]
Common Mistakes:
  • Interpreting OCP as no code changes ever allowed
  • Ignoring the role of abstraction in OCP
  • Underestimating OCP's impact on bug reduction
5. What is a key limitation or trade-off of using method overloading extensively in a large codebase?
medium
A. It can cause ambiguity errors at compile time if parameter lists are too similar or implicit conversions apply
B. It increases runtime overhead due to dynamic dispatch and vtable lookups
C. It prevents subclasses from overriding methods with the same name
D. It requires all overloaded methods to have the same return type

Solution

  1. Step 1: Understand overloading resolution

    Overloading is resolved at compile time by matching method signatures.
  2. Step 2: Identify ambiguity risk

    If parameter lists are too similar or implicit conversions exist, the compiler may not decide which method to call, causing ambiguity errors.
  3. Step 3: Analyze options

    It can cause ambiguity errors at compile time if parameter lists are too similar or implicit conversions apply correctly identifies this compile-time ambiguity risk. It increases runtime overhead due to dynamic dispatch and vtable lookups incorrectly attributes runtime overhead to overloading (it's compile-time). It prevents subclasses from overriding methods with the same name is false; overloading does not prevent overriding. It requires all overloaded methods to have the same return type is false; return types can differ in overloading.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    Overloading can cause compile-time ambiguity, not runtime overhead or overriding restrictions.
Hint: Overloading ambiguity arises from similar parameter lists, not runtime costs
Common Mistakes:
  • Confusing overloading with overriding runtime costs
  • Believing overloading restricts subclass method overriding
  • Assuming return types must be identical in overloading