# Single Responsibility and Open/Closed — Object-Oriented Programming (OOP)

Source: https://www.skillbyai.com/en/oop/s-srp-ocp

> Apply SRP and OCP to keep classes focused and extensible.

## Two principles about change

**SOLID** is an acronym popularised by Robert C. Martin for five object-oriented design principles. The **Single Responsibility Principle (SRP)**: a class should have **one reason to change**, meaning it serves one actor or concern. An `Invoice` class that calculates totals, formats PDFs and sends emails has three reasons to change (tax rules, layout, mail provider); splitting it into `InvoiceCalculator`, `InvoicePdfRenderer` and `InvoiceMailer` keeps each change local. The **Open/Closed Principle (OCP)**, from Bertrand Meyer: software entities should be **open for extension but closed for modification**. Adding a new payment method or discount type should mean **adding a new class** that implements an interface, not editing a growing `if/else` or `switch` in existing, tested code. Apply OCP where variation is **likely**; designing extension points for everything adds complexity without benefit.

## One reason to change each

A class doing many jobs is split into focused classes, each changing for one reason.

![A large block split into three smaller blocks, each with a single small gear icon.](assets/figures/oop/section-6-map.svg) — Figure 6.1 — Splitting responsibilities and extending through new classes.

## Open/closed with a discount strategy

New discount types are new classes; Checkout never changes.

```java
// before: every new discount edits this method
long discountFor(Order o, String type) {
    if (type.equals("FESTIVE")) return o.totalPaise() / 10;
    else if (type.equals("STUDENT")) return 5000;
    else if (type.equals("FIRST_ORDER")) return Math.min(o.totalPaise() / 5, 20000);
    return 0;
}

// after: closed for modification, open for extension
public interface Discount {
    long amountPaise(Order order);
}
public final class FestiveDiscount implements Discount {
    public long amountPaise(Order o) { return o.totalPaise() / 10; }
}
public final class StudentDiscount implements Discount {
    public long amountPaise(Order o) { return 5000; }
}

public final class Checkout {
    public long payable(Order order, Discount discount) {
        return order.totalPaise() - discount.amountPaise(order);
    }
}
```

## SRP is about reasons to change, not number of methods

A class with ten small methods can satisfy SRP; a class with two methods for unrelated concerns may not. Ask who would request a change to this class, and whether they are different people or teams.

**Quiz:** According to the Open/Closed Principle, how should a new payment method usually be added?

- [ ] Edit a large switch statement in existing code
- [ ] Copy the whole payment module
- [x] Add a new class implementing an existing interface
- [ ] Make all fields public

*Answer:* Add a new class implementing an existing interface. OCP favours extension through new implementations rather than modifying tested code.
