Bird
Raised Fist0
Interview Prepoop-design-patternsmediumAmazonGoogleMicrosoftFlipkartRazorpaySwiggy

Abstraction - Abstract Class vs Interface - When to Use Which

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

Define Abstract Class Shape

We start by defining an abstract class named 'Vehicle' with protected fields and an abstract method 'move'. This sets the base for shared behavior.

💡 Defining an abstract class establishes a common template with some implemented details and some abstract methods to be implemented by subclasses.
Line:abstract class Vehicle { protected int speed; public abstract void move(); }
💡 Abstract classes can have fields and abstract methods, allowing partial implementation.
📊
Abstraction - Abstract Class vs Interface - When to Use Which - Watch the Algorithm Execute, Step by Step
Watching this visualization helps you grasp the conceptual differences and usage scenarios of abstract classes and interfaces by seeing their structure and relationships evolve incrementally.
Step 1/11
·Active fillAnswer cell
Demonstrates abstraction by defining an abstract class with fields and abstract methods.
«abstract»Vehicle
#speed: int
+move()
Defines an interface to specify behavior without implementation.
«abstract»Vehicle
#speed: int
+move()
«interface»Movable
+move()
Shows concrete class inheriting from abstract class and implementing abstract methods.
«abstract»Vehicle
#speed: int
+move()
«interface»Movable
+move()
Car
+move()
Car Vehicle (1:1)
Shows concrete class implementing an interface and fulfilling its contract.
«abstract»Vehicle
#speed: int
+move()
«interface»Movable
+move()
Car
+move()
Bike
+move()
Car Vehicle (1:1)Bike Movable (1:1)
Emphasizes abstract class capabilities for code reuse and state.
«abstract»Vehicle
#speed: int
+move()
«interface»Movable
+move()
Car
+move()
Bike
+move()
Car Vehicle (1:1)Bike Movable (1:1)
Emphasizes interface role in multiple inheritance and pure abstraction.
«abstract»Vehicle
#speed: int
+move()
«interface»Movable
+move()
Car
+move()
Bike
+move()
Car Vehicle (1:1)Bike Movable (1:1)
Demonstrates inherited fields usage in concrete subclass.
«abstract»Vehicle
#speed: int
+move()
«interface»Movable
+move()
Car
#speed: int
+move()
Bike
+move()
Car Vehicle (1:1)Bike Movable (1:1)
Shows interface implementation without inherited fields.
«abstract»Vehicle
#speed: int
+move()
«interface»Movable
+move()
Car
#speed: int
+move()
Bike
+move()
Car Vehicle (1:1)Bike Movable (1:1)
Decision step emphasizing abstract class use for shared state.
«abstract»Vehicle
#speed: int
+move()
«interface»Movable
+move()
Car
#speed: int
+move()
Bike
+move()
Car Vehicle (1:1)Bike Movable (1:1)
Decision step emphasizing interface use for multiple behavior contracts.
«abstract»Vehicle
#speed: int
+move()
«interface»Movable
+move()
Car
#speed: int
+move()
Bike
+move()
Car Vehicle (1:1)Bike Movable (1:1)
Final summary of abstraction usage guidelines.
«abstract»Vehicle
#speed: int
+move()
«interface»Movable
+move()
Car
#speed: int
+move()
Bike
+move()
Car Vehicle (1:1)Bike Movable (1:1)

Key Takeaways

Abstract classes allow sharing code and state among related classes while enforcing some methods to be implemented.

This is hard to see from code alone because the combination of implemented and abstract members is subtle without visualization.

Interfaces define pure behavior contracts without state, enabling multiple inheritance and flexible design.

Visualizing the lack of fields and the implementation relationship clarifies interface purpose better than reading code.

Choosing between abstract class and interface depends on whether shared state or multiple behavior contracts are needed.

The decision steps explicitly show criteria that are often implicit or scattered in textual explanations.

Practice

(1/5)
1. Trace the sequence of events when a client calls a method on a subclass instance that violates the Liskov Substitution Principle by strengthening a postcondition. What happens step-by-step?
easy
A. The client receives a result that meets the superclass contract, so no issues arise.
B. The subclass method returns a stricter result than expected, potentially causing client failures.
C. The client silently ignores the stricter postcondition, so behavior is unaffected.
D. The subclass method throws an exception due to the strengthened postcondition.

Solution

  1. Step 1: Recall LSP postcondition rule

    Subclasses must not strengthen postconditions; they can only maintain or weaken them.
  2. Step 2: Trace client call

    The client expects results conforming to the superclass contract. If subclass returns stricter results, some clients expecting broader results may fail.
  3. Step 3: Analyze options

    The subclass method returns a stricter result than expected, potentially causing client failures. correctly identifies potential client failures due to stricter postconditions. The client receives a result that meets the superclass contract, so no issues arise. is false because stricter postconditions can break clients. The client silently ignores the stricter postcondition, so behavior is unaffected. is incorrect; clients cannot ignore contract violations silently. The subclass method throws an exception due to the strengthened postcondition. is not guaranteed; exceptions are not implied by postcondition strengthening.
  4. Final Answer:

    Option B -> Option B
  5. Quick Check:

    Strengthening postconditions risks breaking client expectations.
Hint: Strengthening postconditions breaks client assumptions and causes failures.
Common Mistakes:
  • Assuming stricter postconditions are safe
  • Believing clients ignore contract violations
  • Confusing exceptions with contract violations
2. Which of the following statements about the Adapter pattern is INCORRECT?
medium
A. Adapter changes the interface of an existing object to match what the client expects
B. Adapter can be implemented using inheritance or composition
C. Adapter adds new functionality to the adapted object without modifying it
D. Adapter is used to simplify a complex subsystem by providing a unified interface

Solution

  1. Step 1: Review Adapter intent

    Adapter converts incompatible interfaces to make them compatible.
  2. Step 2: Check each statement

    A is correct: Adapter changes interface. B is correct: Adapter can use inheritance or composition. C is correct: Adapter can add behavior without modifying original object. D is incorrect: Simplifying a complex subsystem is Facade's role, not Adapter's.
  3. Final Answer:

    Option D -> Option D
Hint: Adapter = interface converter; Facade = interface simplifier
Common Mistakes:
  • Confusing Adapter with Facade's simplification role
  • Thinking Adapter only uses inheritance
  • Assuming Adapter cannot add new behavior
3. Which of the following statements about composition and inheritance is INCORRECT?
medium
A. Composition leads to tighter coupling between classes than inheritance.
B. Inheritance models 'is-a' relationships, while composition models 'has-a' relationships.
C. Favoring composition improves flexibility and maintainability of code.
D. Inheritance can cause fragile base class problems when base classes change.

Solution

  1. Step 1: Analyze each statement

    Options A, C, and D are correct statements. Composition leads to tighter coupling between classes than inheritance. is incorrect because composition reduces coupling by separating concerns, whereas inheritance creates tighter coupling due to dependency on base classes.
  2. Final Answer:

    Option A -> Option A
  3. Quick Check:

    Composition reduces coupling; inheritance increases it.
Hint: Composition reduces coupling; inheritance increases coupling.
Common Mistakes:
  • Confusing which relationship leads to tighter coupling
  • Assuming composition increases coupling
4. Which of the following statements about the Liskov Substitution Principle is INCORRECT?
medium
A. A subclass can strengthen preconditions of an inherited method to ensure better input validation.
B. A subclass must not weaken postconditions of an inherited method.
C. Covariance in return types is allowed under LSP.
D. Contravariance in method parameter types is allowed under LSP.

Solution

  1. Step 1: Recall LSP precondition rule

    Subclasses must not strengthen preconditions; they can only maintain or weaken them.
  2. Step 2: Analyze each statement

    A subclass can strengthen preconditions of an inherited method to ensure better input validation. is incorrect because strengthening preconditions breaks substitutability. A subclass must not weaken postconditions of an inherited method. is correct; subclasses can weaken postconditions. Covariance in return types is allowed under LSP. is correct; covariance in return types is allowed. Contravariance in method parameter types is allowed under LSP. is correct; contravariance in parameter types is allowed.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Strengthening preconditions violates LSP.
Hint: Preconditions can only be weakened, not strengthened, in subclasses.
Common Mistakes:
  • Confusing precondition and postcondition rules
  • Believing strengthening preconditions is safe
  • Misunderstanding covariance and contravariance
5. In a language that supports multiple inheritance with MRO, what happens if two parent classes define a method with the same name, but one parent class inherits from the other (forming a diamond), and the child class overrides that method? How does the MRO affect which method is called when the child class method calls super()?
hard
A. super() follows the MRO linearization, calling the next method in the MRO sequence, which may skip some classes.
B. super() calls the method from the immediate parent class only, ignoring the diamond structure.
C. super() calls all parent methods with the same name in parallel, combining their effects.
D. super() always calls the method from the base class at the top of the diamond first.

Solution

  1. Step 1: Understand super() in multiple inheritance

    super() does not simply call the immediate parent but follows the MRO linearization.
  2. Step 2: MRO linearization

    MRO creates a linear order of classes to avoid ambiguity and duplication, so super() calls the next method in this order.
  3. Step 3: Eliminate incorrect options

    super() calls the method from the immediate parent class only, ignoring the diamond structure is incorrect because super() is not limited to immediate parent. super() calls all parent methods with the same name in parallel, combining their effects is wrong because super() does not call methods in parallel. super() always calls the method from the base class at the top of the diamond first is incorrect because super() does not always start at the base class.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    super() respects MRO linearization, ensuring consistent method calls in diamond inheritance.
Hint: super() = next in MRO chain
Common Mistakes:
  • Thinking super() calls only immediate parent
  • Believing super() calls all parents simultaneously
  • Assuming super() always calls base class first