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.
setup
Define Interface Shape
Next, we define an interface named 'Movable' with a single method 'move'. Interfaces declare behavior without implementation or fields.
💡 Interfaces specify a contract that implementing classes must fulfill, focusing purely on method signatures.
Line:interface Movable {
void move();
}
💡 Interfaces cannot have fields and only declare methods to be implemented.
fill_row
Create Concrete Class Car Extending Abstract Class
We define a concrete class 'Car' that extends the abstract class 'Vehicle' and implements the abstract method 'move'.
💡 Concrete classes provide implementations for abstract methods and inherit fields from abstract classes.
Line:class Car extends Vehicle {
public void move() {
// implementation
}
}
💡 Abstract classes allow sharing code and state while requiring subclasses to implement abstract methods.
fill_row
Create Concrete Class Bike Implementing Interface
We define a concrete class 'Bike' that implements the 'Movable' interface and provides the 'move' method implementation.
💡 Implementing an interface requires providing concrete implementations for all declared methods.
Line:class Bike implements Movable {
public void move() {
// implementation
}
}
💡 Interfaces enforce a contract without providing state or implementation.
compare
Highlight Abstract Class Advantages
We highlight that abstract classes can have fields and implemented methods, allowing code reuse and shared state.
💡 Understanding what abstract classes provide beyond interfaces clarifies when to use them.
Line:// Abstract class can have fields and implemented methods
💡 Abstract classes support partial implementation and state sharing.
compare
Highlight Interface Advantages
We highlight that interfaces allow multiple inheritance and define a strict contract without state.
💡 Interfaces enable flexible design by allowing classes to implement multiple behaviors.
Line:// Interface supports multiple inheritance and no state
💡 Interfaces provide a pure abstraction layer for behavior specification.
traverse
Show Concrete Class Using Abstract Class State
We illustrate that 'Car' inherits the 'speed' field from 'Vehicle' and can use it in its methods.
💡 This shows how abstract classes can share state with subclasses, reducing duplication.
Line:class Car extends Vehicle {
public void move() {
speed += 10;
}
}
💡 Abstract classes enable sharing fields and behavior with subclasses.
traverse
Show Concrete Class Implementing Interface Method
We show 'Bike' implements the 'move' method from 'Movable' interface without any inherited state.
💡 This highlights that interfaces only require method implementation, no shared fields.
Line:class Bike implements Movable {
public void move() {
// implementation without inherited fields
}
}
💡 Interfaces enforce behavior contracts without state inheritance.
decision
Decision: Use Abstract Class When Sharing State
We decide that abstract classes are preferred when subclasses share common state or behavior that can be partially implemented.
💡 This decision clarifies when to choose abstract classes over interfaces.
Line:// Use abstract class if shared state or partial implementation needed
💡 Abstract classes enable code reuse and state sharing among related classes.
decision
Decision: Use Interface for Multiple Behavior Contracts
We decide that interfaces are preferred when multiple unrelated classes need to share behavior contracts without sharing state.
💡 This decision clarifies when interfaces provide design flexibility through multiple inheritance.
Line:// Use interface for multiple inheritance and pure abstraction
💡 Interfaces enable flexible design by allowing classes to implement multiple behaviors.
reconstruct
Summarize When to Use Abstract Class vs Interface
We summarize that abstract classes are best for shared code and state, while interfaces are best for defining multiple behavior contracts without state.
💡 This final step consolidates the key differences and usage guidelines.
Line:// Abstract class: shared state and partial implementation
// Interface: multiple inheritance and pure abstraction
💡 Clear criteria help choose the right abstraction mechanism in OOP design.
from abc import ABC, abstractmethod
# STEP 1
class Vehicle(ABC):
def __init__(self):
self._speed = 0 # protected field
@abstractmethod
def move(self):
pass
# STEP 2
class Movable(ABC):
@abstractmethod
def move(self):
pass
# STEP 3
class Car(Vehicle):
def move(self):
self._speed += 10 # implementation
# STEP 4
class Bike(Movable):
def move(self):
# implementation without shared state
pass
# STEP 7
car = Car()
car.move() # uses inherited speed
# STEP 8
bike = Bike()
bike.move() # implements interface method
📊
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 fill★Answer 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 tries to update a private field via a setter method in an encapsulated class.
easy
A. The client directly modifies the private field without any method call
B. The getter method is called first to check the current value before updating
C. The setter method validates the input, updates the private field, then returns control to the client
D. The private field is copied to a public variable which the client modifies
Solution
Step 1: Identify encapsulation flow
Private fields cannot be accessed directly; setters provide controlled access.
Step 2: Follow setter method process
Setter receives input, validates it, updates the private field, then returns control.
Step 3: Analyze incorrect options
The client directly modifies the private field without any method call violates data hiding. The getter method is called first to check the current value before updating misuses getter before setter. The private field is copied to a public variable which the client modifies breaks encapsulation by exposing private data.
Final Answer:
Option C -> Option C
Quick Check:
Setters control updates with validation, preserving encapsulation.
Hint: Setters validate and update private data, not direct access [OK]
Common Mistakes:
Assuming direct field access through setters
Confusing getter and setter roles
Thinking private data is copied out for modification
2. You need to traverse a tree-like structure where each node can be either a single element or a composite containing multiple child elements. The traversal should allow clients to iterate over all elements uniformly without exposing the internal structure. Which design approach best fits this requirement?
easy
A. Implement the Composite pattern combined with an Iterator interface to provide a unified traversal abstraction.
B. Use a recursive brute force traversal that manually visits each node and its children.
C. Apply a greedy algorithm that visits nodes based on a heuristic to minimize traversal time.
D. Use dynamic programming to store and reuse traversal results for overlapping subtrees.
Solution
Step 1: Understand the problem structure
The problem involves a tree with nodes that can be leaves or composites containing children, requiring uniform traversal.
Step 2: Identify the suitable pattern
The Composite pattern allows treating individual objects and compositions uniformly, and combining it with an Iterator abstracts traversal details.
Hint: Composite + Iterator unifies traversal of tree structures [OK]
Common Mistakes:
Confusing traversal with greedy or DP approaches
Using manual recursion without abstraction
3. What is a key trade-off or limitation when using multiple inheritance to solve the Diamond Problem in object-oriented design?
medium
A. Multiple inheritance always leads to ambiguous method calls that cannot be resolved.
B. Multiple inheritance eliminates the need for Method Resolution Order (MRO).
C. Multiple inheritance reduces code reuse compared to single inheritance.
D. Using multiple inheritance can increase complexity and make the class hierarchy harder to understand and maintain.
Solution
Step 1: Understand the Diamond Problem
Diamond Problem arises when a class inherits from two classes that share a common ancestor, causing ambiguity.
Step 2: Evaluate Multiple inheritance always leads to ambiguous method calls that cannot be resolved.
Multiple inheritance can cause ambiguity, but languages use MRO to resolve it, so it is not always unresolved.
Step 3: Evaluate Multiple inheritance eliminates the need for Method Resolution Order (MRO).
MRO is essential in multiple inheritance to resolve method calls, so multiple inheritance does not eliminate MRO.
Step 4: Evaluate Multiple inheritance reduces code reuse compared to single inheritance.
Multiple inheritance generally increases code reuse by combining features from multiple classes.
Step 5: Correct trade-off
Using multiple inheritance can increase complexity and make the class hierarchy harder to understand and maintain. correctly identifies that multiple inheritance increases complexity and can make hierarchies harder to maintain.
Final Answer:
Option D -> Option D
Quick Check:
Complexity and maintainability are key trade-offs in multiple inheritance.
Hint: Multiple inheritance = power with complexity cost
Thinking MRO is unnecessary with multiple inheritance
Assuming multiple inheritance reduces code reuse
4. Suppose you want to extend the Command Pattern to support commands that can be executed multiple times (reused) and also support undo/redo correctly. Which modification to the invoker's undo/redo management is necessary to handle this scenario without corrupting state?
hard
A. Store only one instance of each command and reuse it for all executions, pushing it multiple times onto undo stack.
B. Clear both undo and redo stacks after every command execution to avoid reuse issues.
C. Create a new command instance for each execution and push that instance onto the undo stack, ensuring undo/redo operate on the correct state snapshot.
D. Avoid using undo/redo stacks and instead recompute state from scratch on each undo or redo.
Solution
Step 1: Understand reuse implications
Reusing the same command instance for multiple executions causes undo/redo to affect the wrong state because the command's internal state may change.
Step 2: Identify correct approach
Creating a new command instance per execution ensures each undo/redo corresponds to the exact executed command instance and its parameters.
Step 3: Confirm undo/redo stack integrity
This approach preserves correct ordering and state consistency during undo/redo operations.
Final Answer:
Option C -> Option C
Quick Check:
New instances per execution prevent state corruption on undo/redo [OK]
Hint: Each execution needs a fresh command instance for correct undo/redo [OK]
Common Mistakes:
Reusing command instances causing incorrect undos
Clearing stacks unnecessarily losing history
5. If the Composite pattern iterator is extended to allow reusing leaf components multiple times during traversal (e.g., shared leaves), which modification is necessary to ensure correct iteration without infinite loops?
hard
A. No change needed; the existing iterator handles reuse naturally.
B. Modify the iterator to push children in original order instead of reversed order.
C. Add a visited set to track and skip already visited components during iteration.
D. Convert the iterator to a recursive traversal to handle reuse correctly.
Solution
Step 1: Understand reuse implications
Reusing leaves means the same component can appear multiple times, risking infinite loops.
Step 2: Identify solution to prevent infinite loops
Tracking visited components prevents revisiting the same node repeatedly during iteration.
Final Answer:
Option C -> Option C
Quick Check:
Visited set avoids infinite loops with shared components [OK]
Hint: Track visited nodes to handle shared components safely [OK]
Common Mistakes:
Assuming no changes needed
Changing push order does not fix reuse loops
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.