Practice
Solution
Step 1: Review inheritance benefits
Inheritance supports code reuse and polymorphism for uniform handling.Step 2: Recognize limitations
Inheritance hierarchies can become rigid and hard to extend, violating open-closed principle.Step 3: Identify incorrect statement
Claiming inheritance is always best ignores alternatives like composition or interfaces that improve extensibility.Final Answer:
Option C -> Option CQuick Check:
Inheritance is not always best for extensibility [OK]
- Assuming inheritance is always the best design choice
- Ignoring polymorphism benefits
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 DQuick Check:
Complexity and maintainability are key trade-offs in multiple inheritance.
- Believing multiple inheritance always causes irresolvable ambiguity
- Thinking MRO is unnecessary with multiple inheritance
- Assuming multiple inheritance reduces code reuse
class Singleton {
private static Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
What is the subtle bug that can cause thread-safety issues?Solution
Step 1: Analyze double-checked locking correctness
Without volatile, the instance reference may be visible before full construction due to instruction reordering.Step 2: Check other options
Synchronized block size is minimal and correct; first null check is necessary for performance; constructor privacy is unrelated to this snippet.Final Answer:
Option B -> Option BQuick Check:
Missing volatile causes subtle thread-safety bugs [OK]
- Ignoring volatile keyword necessity
- Thinking synchronized block size is the bug
- Assuming constructor privacy is the main issue here
class PaymentProcessor:
def __init__(self, strategy: PaymentStrategy):
self.strategy = strategy
def pay(self, amount):
if isinstance(self.strategy, CreditCardStrategy):
print(f"Processing credit card payment of ${amount}")
elif isinstance(self.strategy, UPIStrategy):
print(f"Processing UPI payment of ${amount}")
else:
print("Invalid payment method")
Solution
Step 1: Analyze the pay method implementation
The pay method usesisinstancechecks and conditionals to decide behavior, which defeats the purpose of polymorphism.Step 2: Identify correct polymorphic usage
The correct approach is to callself.strategy.pay(amount)directly, letting each strategy handle its own payment logic.Final Answer:
Option A -> Option AQuick Check:
Using conditionals in pay() breaks the strategy pattern [OK]
- Using type checks instead of polymorphism
Solution
Step 1: Understand LSP behavioral contract
LSP requires that subclasses preserve the observable behavior of the superclass, including side effects.Step 2: Analyze covariant return type
Covariant return types are allowed and safe, but side effects must still comply with the superclass contract.Step 3: Evaluate options
Refactor the subclass to preserve the original side effects or weaken them, ensuring behavioral compatibility. correctly suggests refactoring to preserve or weaken side effects. Allow the side effect changes since the return type is covariant and thus safe. is incorrect; side effect changes can break clients. Ignore side effects as they are not part of the method signature and thus irrelevant to LSP. is false; side effects are part of behavior and relevant. Change the superclass method to accommodate the subclass's side effects. is risky and breaks superclass abstraction.Final Answer:
Option C -> Option CQuick Check:
Behavioral compatibility includes side effects, not just signatures.
- Ignoring side effects in LSP
- Assuming covariant return types cover all behavioral changes
- Modifying superclass to fit subclass
