SSD Study Reference

Score: 0/0

Quick Reference

Core principles and patterns from Lectures 2 & 3. Each card: definition, key rule, classic violation, fix.

SRP Single Responsibility

A class should have one and only one reason to change.

Key Rule

Each class encapsulates exactly one responsibility.

Classic Violation

An Invoice class that calculates totals, sends emails, and saves to DB.

Fix

Extract into Mailer, SalesTax, and InvoiceRepository classes.

OCP Open/Closed

Open for extension, closed for modification.

Key Rule

Add new behavior without changing existing code. Rely on abstractions.

Classic Violation

AreaCalculator.sum() with if/else chains for each shape type.

Fix

Define ShapeInterface with area(); each shape implements it. Calculator iterates the interface.

LSP Liskov Substitution

Subtypes must be substitutable for their base types without breaking behavior.

Key Rule

Child classes must not remove base class behavior or violate invariants.

Classic Violation

A Square overriding volume() to throw an exception or return 0.

Fix

Separate ShapeInterface (area) from ThreeDShapeInterface (volume).

ISP Interface Segregation

Clients should not be forced to depend on methods they do not use.

Key Rule

Several specialized interfaces are better than one all-purpose interface.

Classic Violation

A Shape interface with both area() and volume() — flat shapes forced to implement volume().

Fix

Split into ShapeInterface and SolidShapeInterface.

DIP Dependency Inversion

Depend on abstractions, not concretions.

Key Rule

High-level modules should not depend on low-level modules. Both depend on abstractions.

Classic Violation

SumCalculatorSaver directly instantiates MySQLDatabase.

Fix

Inject a DatabaseInterface. Swap MySQL, Postgres, etc. without changing the saver.

Strategy Strategy Pattern

Define a family of algorithms, encapsulate each, make them interchangeable. Behavioral.

Key Rule

Uses composition: context holds a reference to a strategy interface, swappable at runtime.

Classic Violation

Giant if/else in Hero.attack() for each attack type.

Fix

AttackStrategy interface; MeleeAttack, RangedAttack classes. Hero calls strategy.attack().

Template Method Template Method Pattern

Define the skeleton of an algorithm in a superclass; subclasses override specific steps. Behavioral.

Key Rule

Uses inheritance: the template method is final in the base class; only hook/abstract steps are overridden.

Classic Violation

Duplicated sorting algorithms that differ only in the comparison step.

Fix

Abstract SortingTool with sort() template method; subclasses override compare().

Singleton Singleton Pattern

Ensure a class has only one instance with a global access point. Creational.

Key Rule

Private constructor + static getInstance() that lazily creates or returns the cached instance.

Classic Violation

Multiple Hero objects created via new Hero() in different parts of the game.

Fix

Private constructor, static instance field, public Hero.getInstance().

Key Distinction Patterns vs. Principles

Design Principles (SOLID): Abstract guidelines, high-level, language-agnostic, not a concrete solution.

Design Patterns: Concrete, proven solutions to recurring problems, low-level technical details.

Strategy vs Template Method

Strategy = composition + interface (swap at runtime). Template Method = inheritance + abstract class (fixed skeleton, override steps).

True / False Quiz

Click True or False. Rationale is revealed immediately. Grouped by topic.

SOLID — Single Responsibility
1. SRP means a class should only have one method.
SRP says a class should have only one reason to change (one responsibility), not one method. A class may have many methods that all serve that single responsibility.
2. If a Report class generates report data AND sends it by email, it violates SRP.
The class has two reasons to change: changes to report logic and changes to email delivery. These are two distinct responsibilities.
3. An object that can save/restore itself is a classic SRP violation.
Persistence is a separate concern. The lecture lists "objects that can save/restore themselves" as a classic SRP violation, recommending a separate saver or memento.
4. SRP applies only to classes, not to methods or modules.
While often discussed at class level, SRP (and all SOLID principles) can and should be applied at method, module, and even service/architecture level, as the lecture explicitly states.
SOLID — Open/Closed
5. The Open/Closed Principle says you should never modify existing source code.
OCP says entities should be open for extension, closed for modification. Bug fixes or internal refactors may still modify code. The goal is that new behavior can be added via extension without changing existing working code.
6. Using if/else chains to handle new shape types in AreaCalculator violates OCP.
Every new shape requires modifying the calculator's code. Using a ShapeInterface with an area() method lets you add shapes without touching the calculator.
7. The Strategy pattern is one way to achieve OCP.
The lecture explicitly lists composition/Strategy pattern as one of three approaches to achieve OCP (alongside parameters/callbacks and inheritance/Template Method).
8. OCP can be achieved by passing delegates or callbacks.
The lecture lists three approaches: (1) parameters/delegates/callbacks, (2) inheritance/Template Method, (3) composition/Strategy pattern.
SOLID — Liskov Substitution
9. If a subclass overrides a method to throw an UnsupportedOperationException, it likely violates LSP.
The lecture states: "If an override method does nothing or throws an exception, you're probably violating LSP." The parent's contract promises that method works.
10. LSP requires that child classes behave identically to parent classes in every scenario.
LSP requires child classes to be substitutable for the parent — they must honor the base class's contract and invariants, but they can extend behavior. They don't have to be identical.
11. A Square class extending Rectangle that overrides setWidth to also set height violates LSP.
Code using Rectangle expects setWidth and setHeight to be independent. A Square breaks this expectation, violating the substitutability contract.
12. If unit tests for the superclass cannot pass when run against a subclass, LSP is violated.
The lecture directly states: "if you do not follow [LSP] the unit test for the superclass would never succeed for the subclasses."
SOLID — Interface Segregation
13. ISP says you should have one interface per class.
ISP says clients should not be forced to depend on methods they don't use. The solution is specialized interfaces — a class may implement multiple interfaces, and different clients depend only on the one they need.
14. A fat interface with methods for both 2D area and 3D volume forces flat shapes to implement volume(), violating ISP.
This is the exact case study from the lecture. The fix is splitting into ShapeInterface (area) and SolidShapeInterface (volume).
15. ISP and SRP are the same principle applied to different things.
While related, SRP is about a class having one responsibility (one reason to change). ISP is about interfaces — no client should depend on methods it doesn't use. A class could satisfy SRP but still implement a fat interface violating ISP.
SOLID — Dependency Inversion
16. DIP says high-level modules should depend on low-level modules.
DIP says the opposite: high-level modules should NOT depend on low-level modules. Both should depend on abstractions.
17. Injecting a DatabaseInterface instead of instantiating MySQLDatabase directly follows DIP.
The high-level class depends on the abstraction (DatabaseInterface) rather than the concrete implementation (MySQLDatabase), exactly what DIP prescribes.
18. DIP only applies to database connections.
DIP is a general principle. Any time a high-level module directly depends on a low-level concrete class, DIP is relevant — logging, networking, file I/O, payment gateways, etc.
Strategy Pattern
19. The Strategy pattern uses inheritance to vary algorithm behavior.
Strategy uses composition, not inheritance. The context holds a reference to a strategy interface. Template Method is the one that uses inheritance.
20. In the Strategy pattern, the client can change the algorithm at runtime.
A key benefit: the context class typically provides a setter to swap strategies at runtime. The Zombie Killer example shows switching attack styles during gameplay.
21. The Strategy pattern eliminates the need for if/else or switch statements to choose algorithms.
The lecture explicitly states Strategy solves the problem "without filling your code with if-else or switch statements." The correct strategy is injected/set externally.
22. In the Shopping Cart example, ShoppingCart knows whether the payment is via PayPal or Credit Card.
ShoppingCart calls paymentMethod.pay(amount) through the PaymentStrategy interface. It doesn't know the concrete type — that's the whole point of the pattern.
23. Adding a new concrete strategy (e.g., MagicalAttack) requires modifying the context class.
The Zombie Killer example shows adding MagicalAttack without changing the Hero class. You just create a new class implementing the strategy interface — this also satisfies OCP.
Template Method Pattern
24. Template Method uses composition to let subclasses override specific algorithm steps.
Template Method uses inheritance. The base class defines the skeleton (template method), and subclasses override specific steps. Strategy uses composition.
25. In Template Method, subclasses can override the template method itself.
The lecture states: "Concrete Classes can override all of the steps, but not the template method itself." The template method defines the fixed skeleton.
26. Template Method is appropriate when algorithms share the same structure but differ in specific steps.
The sorting tool example: all sorting algorithms share init-compare-return structure but differ in the compare step. The shared structure is the template method.
27. Strategy and Template Method solve the same kind of problem but differ in mechanism — composition vs. inheritance.
The lecture directly compares them: Strategy is composition-based (swap via interface), Template Method is inheritance-based (override via subclass).
Singleton Pattern
28. Singleton is a behavioral design pattern.
Singleton is a creational design pattern. It deals with object creation (ensuring only one instance is created).
29. In Singleton, the constructor is made private to prevent external instantiation.
The lecture states: "Make the default constructor private, to prevent other objects from using the new operator with the Singleton class."
30. Singleton provides a global access point to the single instance.
The lecture defines Singleton as ensuring "a class has only one instance, while providing a global access point to this instance."
31. In the Zombie Killer game, Singleton is used because there should be only one Hero instance shared across all client classes.
The lecture shows multiple client classes all needing the same Hero instance. Singleton ensures one shared Hero with a consistent state.
Mixed Concepts
32. Design patterns are abstract guidelines while SOLID principles are concrete solutions.
It's the opposite. SOLID principles are abstract, high-level guidelines. Design patterns are concrete, proven solutions to recurring problems with technical details.
33. Design patterns are classified into Creational, Structural, and Behavioral categories.
The lecture lists: Creational (object creation), Structural (how objects are connected), Behavioral (communication between objects).
34. The Strategy pattern can help satisfy OCP because new strategies can be added without modifying existing code.
Adding a new concrete strategy class extends behavior without modifying the context or other strategies. This directly satisfies OCP.
35. A class using Singleton pattern and Strategy pattern at the same time is impossible — they are mutually exclusive.
They are NOT mutually exclusive. The Zombie Killer case study combines both: Hero is a Singleton AND uses Strategy for attack styles.

Scenario Problems

Original scenarios at tiered difficulty. Pick an answer, then read the detailed explanation.

Tier 1 — Warm-Up

Warm-Upclick to collapse
Scenario 1
A UserService class handles user registration, sends a welcome email, and writes a log entry to a file. A teammate asks you to review it. Which principle is violated?
SRP Violation. UserService has three reasons to change: registration logic, email delivery mechanism, and logging format/destination. Extract into UserRegistrar, WelcomeMailer, and Logger classes, each with a single responsibility.
Scenario 2
A NotificationSender class has a method send() with a switch statement: case "sms", case "email", case "push". To add Slack notifications, a developer must edit this method. What is the issue?
OCP Violation. Every new notification channel requires modifying the existing send() method. Fix: define a NotificationStrategy interface with send(), and create SmsNotification, EmailNotification, PushNotification, SlackNotification as concrete strategies. The sender calls strategy.send() without needing to change.
Scenario 3
A game has a Vehicle base class with a fly() method. Car extends Vehicle and overrides fly() to throw UnsupportedOperationException. What is the primary violation?
LSP Violation. Any code using Vehicle expects fly() to work. Car breaks this contract by throwing an exception. Fix: separate into Drivable and Flyable interfaces. Only classes that actually fly implement Flyable. This also fixes the ISP issue of forcing non-flying vehicles to have fly().
Scenario 4
A food delivery app needs to calculate delivery fees differently: standard delivery, express delivery, and drone delivery. The fee algorithm may change or new delivery types may be added. Which pattern?
Strategy Pattern. You have a family of interchangeable algorithms (fee calculations) that should be swappable at runtime. Define DeliveryFeeStrategy interface with calculateFee(). Concrete classes: StandardFee, ExpressFee, DroneFee. The Order context holds a reference to the strategy and can switch dynamically.
Scenario 5
An application needs exactly one database connection pool shared across all services. Multiple calls to create the pool must return the same instance. Which pattern?
Singleton Pattern. You need to guarantee exactly one instance with global access. Make the ConnectionPool constructor private, add a static getInstance() that lazily creates or returns the cached pool. All services call ConnectionPool.getInstance().

Tier 2 — Intermediate

Intermediateclick to collapse
Scenario 6
A ReportGenerator class creates reports in PDF, Excel, and HTML. It has a method generate(String type) that switches on the type to build each format. The same class also emails the report. A new CSV format is requested. What are the violations?
SRP + OCP Violation. First, SRP: the class both generates reports and emails them — extract ReportMailer. Second, OCP: the switch on type means adding CSV requires modifying existing code. Fix: ReportFormatStrategy interface with generate(), concrete classes per format. The generator is closed for modification when new formats arrive.
Scenario 7
A CI/CD pipeline has three stages: checkout then build then deploy. The checkout and deploy steps are always the same, but the build step differs: Java projects use Maven, Node projects use npm, Python projects use pip. Which pattern fits best?
Template Method Pattern. The pipeline has a fixed sequence (skeleton): checkout, build, deploy. Only the build step varies. Create an abstract Pipeline with a final run() method that calls checkout(), build(), deploy(). The build() method is abstract, overridden by JavaPipeline, NodePipeline, PythonPipeline. This is inheritance-based because the structure is fixed.
Scenario 8
Consider this design:
class OrderProcessor { private MySQLDatabase db = new MySQLDatabase(); void process(Order o) { db.save(o); } }
The team wants to switch to PostgreSQL for some deployments. What's the issue?
DIP + OCP Violation. DIP: OrderProcessor (high-level) directly depends on MySQLDatabase (low-level concrete). OCP: switching databases requires modifying the processor. Fix: define DatabaseInterface with save(). Inject via constructor: OrderProcessor(DatabaseInterface db). Now both MySQL and Postgres implement the interface, and the processor never changes.
Scenario 9
A MediaPlayer interface has methods: playAudio(), playVideo(), streamLive(). A PodcastPlayer class implements it but only needs playAudio(). It throws exceptions for playVideo() and streamLive(). Identify the violations.
ISP + LSP Violation. ISP: PodcastPlayer is forced to depend on playVideo() and streamLive() which it doesn't use. LSP: any code expecting a MediaPlayer will break when calling video/stream on a PodcastPlayer. Fix: split into AudioPlayable, VideoPlayable, LiveStreamable. PodcastPlayer implements only AudioPlayable.
Scenario 10
A logging framework must support Console, File, and Cloud logging. All loggers follow the same flow: format message, then apply filter, then write output. The "write output" step differs per destination. Which pattern — and why NOT the other?
Both could work, but Template Method is more natural. The algorithm has a fixed 3-step structure (format, filter, write) with only the final step varying. Template Method captures this perfectly: abstract Logger with final log() calling format(), filter(), write(). Subclasses override only write(). Strategy would also work (inject a Writer), but you'd lose the guaranteed shared structure. When the skeleton is fixed and only specific steps vary, Template Method is the better fit.

Tier 3 — Advanced

Advancedclick to collapse
Scenario 11
A multiplayer game has a GameServer that must be a single instance. Players can choose combat styles (Melee, Ranged, Stealth) that are swappable during gameplay. The game also processes turn sequences: startTurn, then executeAction, then endTurn — where executeAction varies by game mode (PvP vs PvE). Identify all applicable patterns.
All three patterns apply. (1) Singleton: GameServer must be a single instance — private constructor, static getInstance(). (2) Strategy: Combat styles are a family of interchangeable algorithms swappable at runtime — CombatStrategy interface with Melee, Ranged, Stealth implementations. (3) Template Method: Turn processing has a fixed skeleton (start, execute, end) with only executeAction varying between PvP and PvE modes — abstract TurnProcessor with final processTurn().
Note how Strategy uses composition (player holds a CombatStrategy reference) while Template Method uses inheritance (PvPTurnProcessor extends TurnProcessor).
Scenario 12
A document editor exports documents. Current code:
class DocExporter { void export(Document doc, String format) { if (format.equals("pdf")) { /* 50 lines */ } else if (format.equals("html")) { /* 50 lines */ } else if (format.equals("docx")) { /* 50 lines */ } } }
Each export follows the same steps: validate, then transform, then write — but the transform and write steps differ per format. The exporter is directly used by a CloudUploader that instantiates it as new DocExporter(). Identify all violations and suggest a redesign.
Three violations: (1) OCP: Adding a new format requires modifying the if/else chain. (2) SRP: One class handles all format-specific logic. (3) DIP: CloudUploader depends on concrete DocExporter. Redesign: Since all exports share validate-transform-write, use Template Method: abstract Exporter with final export() calling validate(), abstract transform(), abstract write(). Concrete: PdfExporter, HtmlExporter, DocxExporter. For DIP: CloudUploader depends on Exporter (abstraction), not a concrete class.
Scenario 13
A smart home system has a DeviceController interface with methods: turnOn(), turnOff(), setTemperature(), setBrightness(), lock(), unlock(). All devices (lights, thermostats, door locks) implement this interface. A SmartHomeApp (high-level) directly creates new PhilipsLight() and new NestThermostat(). Identify violations and fix.
ISP + DIP Violations. ISP: Lights don't need setTemperature/lock/unlock; thermostats don't need setBrightness/lock/unlock; locks don't need setTemperature/setBrightness. Fix: split into Switchable (turnOn/Off), TemperatureControllable (setTemperature), Dimmable (setBrightness), Lockable (lock/unlock). Each device implements only relevant interfaces. DIP: SmartHomeApp (high-level) directly instantiates concrete device classes. Fix: inject devices via constructor using their interface types.
This also prevents LSP issues — a Light won't need to throw exceptions for lock() since it never implements Lockable.
Scenario 14
A report engine produces weekly and monthly reports. Both follow: fetchData, then analyze, then formatOutput. The analysis step differs, but everything else is the same. Currently, both report types independently implement all three steps with copy-pasted code. A new quarterly report is needed. Additionally, the output format (PDF vs CSV) should be swappable at runtime. Which combination of patterns?
Template Method + Strategy. The report skeleton (fetch, analyze, format) is fixed with only the analyze step varying per report type — this is a textbook Template Method: abstract Report with final generate(), abstract analyze(). Subclasses: WeeklyReport, MonthlyReport, QuarterlyReport. For the output format (PDF vs CSV) that must be swappable at runtime, use Strategy: OutputFormatStrategy interface with PdfFormat and CsvFormat. The Report class holds a strategy reference for formatting.
Key insight: Template Method for the inheritance-based fixed skeleton (what steps to run), Strategy for the composition-based runtime choice (how to format output).

Tier 4 — Exam-Level

Exam-Levelclick to collapse
Scenario 15
A ride-sharing app has this design:
class RideManager { private MySQLDatabase db = new MySQLDatabase(); double calculateFare(Ride ride) { if (ride.type.equals("economy")) return ride.distance * 1.0; else if (ride.type.equals("premium")) return ride.distance * 2.5; else if (ride.type.equals("pool")) return ride.distance * 0.7; } void saveRide(Ride ride) { db.save(ride); } void sendReceipt(Ride ride) { EmailService.send(ride); } void logRide(Ride ride) { FileLogger.log(ride); } }
The team needs to add "luxury" rides and switch from MySQL to MongoDB. Identify ALL violated SOLID principles and propose a redesign.
Three SOLID violations:

1. SRP Violation: RideManager has four responsibilities — fare calculation, persistence, emailing receipts, and logging. Each is a separate reason to change. Fix: Extract FareCalculator, RideRepository, ReceiptMailer, RideLogger.

2. OCP Violation: Adding "luxury" rides requires modifying the if/else chain in calculateFare(). Fix: Use Strategy PatternFareStrategy interface with EconomyFare, PremiumFare, PoolFare, LuxuryFare.

3. DIP Violation: RideManager directly depends on MySQLDatabase (concrete), EmailService (concrete), and FileLogger (concrete). Fix: Define abstractions: DatabaseInterface, NotificationService, Logger. Inject via constructor.

Complete redesign: RideManager becomes a thin coordinator. FareCalculator uses Strategy for fare types. All dependencies injected as abstractions. Adding luxury = new FareStrategy class. Switching to MongoDB = new DatabaseInterface implementation. Zero existing code modified.
Scenario 16
An e-learning platform has this interface and classes:
interface Course { void playVideo(); void downloadPDF(); void submitAssignment(); void takeQuiz(); void joinLiveSession(); } class RecordedCourse implements Course { // joinLiveSession() throws UnsupportedOperationException } class LiveCourse implements Course { // downloadPDF() throws UnsupportedOperationException } class ReadingCourse implements Course { // playVideo(), joinLiveSession(), takeQuiz() // all throw UnsupportedOperationException }
A LearningApp class does new RecordedCourse() directly. Enrollment follows the same flow for all courses: register, then enroll, then startLearning — but startLearning differs per course type. Identify all violations and design the fix.
Four issues identified:

1. ISP Violation: The fat Course interface forces all course types to implement methods they don't support. Fix: Split into Watchable (playVideo), Downloadable (downloadPDF), Assignable (submitAssignment), Quizzable (takeQuiz), LiveJoinable (joinLiveSession). Each course implements only relevant interfaces.

2. LSP Violation: RecordedCourse, LiveCourse, and ReadingCourse all throw exceptions for inherited methods, breaking substitutability. Fixed automatically by the ISP fix — classes only implement what they support.

3. DIP Violation: LearningApp uses new RecordedCourse() — depends on concrete type. Fix: inject via interface types.

4. Template Method: Enrollment flow (register, enroll, startLearning) is a fixed skeleton with one varying step. Abstract EnrollmentProcess with final enroll() template method; subclasses override startLearning().

This mirrors the lecture's Shape Calculator evolution: a fat interface causes ISP+LSP violations; splitting interfaces and using the right pattern (Template Method for fixed flow) gives a clean, extensible design.
Scenario 17
A warehouse robot system has:
class WarehouseController { private static WarehouseController instance; void pickItem(String strategy) { if (strategy.equals("nearest")) { /* nearest-first logic */ } else if (strategy.equals("priority")) { /* high-priority first */ } else if (strategy.equals("fifo")) { /* first-in-first-out */ } } void executeTask() { // Always: scanBarcode, pickItem, placeOnBelt // scanBarcode and placeOnBelt are always the same // pickItem varies as above } void saveToDatabase() { PostgresDB db = new PostgresDB(); db.save(this); } }
The team needs to: (1) add a new "batch" picking strategy, (2) support different task sequences for fragile items where scanning is more careful, (3) switch to a cloud database. This class has issues with almost every principle and pattern from the course. Identify all issues and redesign completely.
Comprehensive analysis — all principles and patterns apply:

SOLID Violations:
- SRP: WarehouseController picks items, executes tasks, AND persists to database — three responsibilities.
- OCP: Adding "batch" picking requires modifying the if/else chain.
- DIP: Directly instantiates PostgresDB inside saveToDatabase().

Pattern Issues:
- Singleton: Has a static instance field but the implementation is incomplete (no private constructor, no getInstance). Fix: proper private constructor + static getInstance().
- Strategy needed: Picking algorithms are a family of interchangeable algorithms: PickingStrategy interface with NearestFirst, PriorityFirst, FIFO, BatchPick.
- Template Method needed: Task execution has a fixed skeleton (scan, pick, place) with the scanning step varying for fragile items: abstract TaskExecutor with final execute(), abstract scan(). StandardTaskExecutor and FragileTaskExecutor override scan().

Redesign:
1. WarehouseController (Singleton) — thin coordinator only
2. PickingStrategy interface — injected into controller (Strategy)
3. Abstract TaskExecutor — skeleton for task sequence (Template Method)
4. DatabaseInterface — injected, not instantiated (DIP)
5. WarehouseRepository — handles persistence (SRP)

This is the "boss level" — it combines every concept from both lectures into one coherent system. The key insight is recognizing WHEN to use Strategy (runtime-swappable algorithms) vs. Template Method (fixed skeleton with varying steps) vs. Singleton (guaranteed single instance), all while respecting SOLID.