Principles + OOP + UML
// Reason 2: DB schema changes void saveToDatabase() { … }
// Reason 3: report format changes void printInvoice() { … }
// Reason 4: email provider changes void sendEmail() { … } }
class Rectangle implements Shape { int area() { return width * height; } }
class Square implements Shape { int area() { return side * side; } } // Both honour the Shape contract ✓
instanceof checks or UnsupportedOperationException throws. These scream "inheritance hierarchy is wrong." Common trap: Penguin extends Bird (fly() throws!).class HumanWorker implements Workable, Feedable, Restable { … }
class RobotWorker implements Workable { … } // Only what it needs — no stubs!
public OrderService() { this.database = new MySQLDatabase(); // ✗ this.emailer = new EmailService(); // ✗ } } // To switch to PostgreSQL — must change OrderService!
class OrderService { private final OrderRepository repo; private final NotificationService notif;
public OrderService(OrderRepository r, NotificationService n) { this.repo = r; this.notif = n; } } // Wiring: new OrderService(new PostgreSQL(), new SMS());
Printable
PricingStrategy
OCP: New vehicle type = new Spot subclass, zero modifications to existing
DIP: PricingStrategy injected — swap hourly/flat without changing Spot
LSP: All Spot subtypes honour canFit() contract — no UnsupportedOperation
For each snippet: name the principle violated, explain why, and write the fixed version.
// Snippet A — which principle?
class Report {
String generateHTML() { ... }
String generatePDF() { ... }
void saveToFile(String path) { ... }
void uploadToS3() { ... }
void emailReport(String to) { ... }
}
// Snippet B — which principle?
class Square extends Rectangle {
void setWidth(int w) { this.width=w; this.height=w; }
void setHeight(int h) { this.width=h; this.height=h; }
}
// Snippet C — which principle?
interface Printable {
void print(); void scan(); void fax(); void copy();
}
class BasicPrinter implements Printable {
void print() { … }
void scan() { throw new UnsupportedOperationException(); }
void fax() { throw new UnsupportedOperationException(); }
void copy() { throw new UnsupportedOperationException(); }
}
// Snippet D — which principle?
class NotificationService {
void notify(String type, String message) {
if (type.equals(“EMAIL”)) sendEmail(message);
else if (type.equals(“SMS”)) sendSMS(message);
else if (type.equals(“PUSH”)) sendPush(message);
}
}
Draw the UML class diagram with these entities. Include all attributes, methods, relationships with correct symbols, and multiplicities.
Entities: Library, Member, Book, BookCopy, Loan, LibrarianRequirements:
- A Library has many Members and many BookCopies
- A Book can have multiple BookCopies
- A Loan connects a Member to a BookCopy (with dates)
- A Librarian manages loans
- Members have a borrowing limit (max 3 books)
- BookCopy has status: AVAILABLE, BORROWED, RESERVED
Include: composition vs aggregation distinction inheritance if Librarian IS-A Member all multiplicities on every relationship
Draw a sequence diagram for the complete order placement flow including the failure path.
Actors: Customer, OrderService, PaymentService,
InventoryService, EmailService
Happy path:
- Customer → OrderService: placeOrder(cart)
- OrderService → PaymentService: validatePayment(card)
- PaymentService → OrderService: paymentConfirmed
- OrderService → InventoryService: reserveItems(cart)
- InventoryService → OrderService: reservationId
- OrderService → EmailService: sendConfirmation(email)
- OrderService → Customer: orderId
Also model: what happens when payment fails?
Show the failure path as an alt block
The violating code below has multiple SOLID violations. List every violation with line references, produce refactored Java code, and draw the UML class diagram of your solution.
class ParkingLot {
private int totalSpots = 100;
private int occupiedSpots = 0;
private List<String[]> parkedVehicles = new ArrayList<>();
public String parkVehicle(String vehicleType, String plate) {
if (occupiedSpots >= totalSpots) return “Lot is full”;
// ← VIOLATION: what principle? why?
double rate;
if (vehicleType.equals("CAR")) rate = 20.0;
else if (vehicleType.equals("BIKE")) rate = 10.0;
else if (vehicleType.equals("TRUCK")) rate = 40.0;
else return "Unknown vehicle type";
// ← VIOLATION: what principle? why?
String ticketId = "T" + System.currentTimeMillis();
parkedVehicles.add(new String[]{ticketId, plate,
vehicleType, String.valueOf(System.currentTimeMillis()),
String.valueOf(rate)});
occupiedSpots++;
// ← VIOLATION: what principle? why?
System.out.println("Parked " + vehicleType);
// ← VIOLATION: what principle? why?
saveToDatabase(ticketId, plate);
return ticketId;
}
private void saveToDatabase(String id, String plate) {
System.out.println(“Saving to MySQL: ” + id); // hardcoded!
}
public double calculateBill(String ticketId) {
// billing logic crammed here ← VIOLATION: what principle?
for (String[] v : parkedVehicles) {
if (v[0].equals(ticketId)) {
long entry = Long.parseLong(v[3]);
double hours = (System.currentTimeMillis()-entry)/3600000.0;
double rate = Double.parseDouble(v[4]);
return Math.ceil(hours) * rate;
}
}
return 0;
}
}
Deliverable:
- List each violation (principle + explanation)
- Refactored Java code (multiple classes)
- UML class diagram of the refactored design