What this topic covers
12 subtopics- Class relationships7
- Dependency inversion7
- Open/closed5
- Coupling and cohesion4
- Liskov substitution4
- Design principles3
- Design smells3
- Interface segregation3
- Single responsibility3
- UML3
- Composition over inheritance2
- Responsibility assignment1
- Beginner 15
- Intermediate 15
- Advanced 15
About this topic
SOLID is five guidelines for classes that are easy to change: Single responsibility, Open/closed, Liskov substitution, Interface segregation and Dependency inversion. Class relationships describe how objects connect: association (knows about), aggregation (has, but parts live independently – hollow diamond), composition (owns, parts die with the whole – filled diamond) and dependency (uses – dashed arrow). Most questions here show a UML class diagram or a short design scenario.
Free preview
Sample questions
Try each one first, then open the answer for the explanation and why the other options are wrong.
What does the Single Responsibility Principle say?
Show answer and explanation
Explanation
If tax rules, PDF layout and database schema all live in one Invoice class, three different teams change it for three reasons. Splitting it keeps changes local.
Why the other options are wrong
- AUnrelated.
- BThat is the Singleton pattern.
- CMethods per class is not the point.
A read-only list extends ArrayList. What does this print?
import java.util.*;
public class Main {
static class ReadOnlyList<E> extends ArrayList<E> {
ReadOnlyList(Collection<E> c) { super(c); }
@Override public boolean add(E e) { throw new UnsupportedOperationException("read-only"); }
}
static int addDefault(List<String> list) {
list.add("default");
return list.size();
}
public static void main(String[] args) {
System.out.print(addDefault(new ArrayList<>(List.of("a"))) + " ");
try {
System.out.print(addDefault(new ReadOnlyList<>(List.of("a"))));
} catch (UnsupportedOperationException e) {
System.out.print(e.getMessage());
}
System.out.println();
}
}
Show answer and explanation
Explanation
addDefault was written against List and works for a normal ArrayList, but the subclass refuses an operation the base type promises – a Liskov violation that only shows up at run time. Separate read-only and writable types (or composition) avoid it.
Why the other options are wrong
- AIt compiles.
- CThe subclass throws.
- DThe plain list works.
New channels are added by wrapping, not by editing Notifier. What does this print?
class Notifier:
def send(self, msg):
return [f"email:{msg}"]
class SmsDecorator:
def __init__(self, inner):
self.inner = inner
def send(self, msg):
return self.inner.send(msg) + [f"sms:{msg}"]
class SlackDecorator:
def __init__(self, inner):
self.inner = inner
def send(self, msg):
return [f"slack:{msg}"] + self.inner.send(msg)
n = SlackDecorator(SmsDecorator(Notifier()))
print(n.send("down"))
Show answer and explanation
Explanation
Each decorator adds behaviour around the object it wraps, and they can be stacked in any combination at run time – no subclass per combination, no change to Notifier. Order matters: Slack prepends, SMS appends.
Why the other options are wrong
- AInner notifiers still run.
- BBoth decorators add entries.
- CSlack adds its entry before the inner result.