개발/자바
OCP(Open-Closed Principle), SRP(Single Responsibility Principle)
피터JK
2025. 2. 19. 17:24
728x90
OCP(Open-Closed Principle, 개방-폐쇄 원칙)
**OCP(Open-Closed Principle)**는 **"소프트웨어 엔티티(클래스, 모듈, 함수 등)는 확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 한다"**는 원칙이다.
- 확장에는 열려 있어야 한다(Open for extension): 새로운 기능을 추가할 때 기존 코드를 변경하지 않고 확장할 수 있어야 한다.
- 수정에는 닫혀 있어야 한다(Closed for modification): 기존 코드가 변경되지 않도록 설계하여 안정성을 유지해야 한다.
📌 OCP를 지키는 방법
- 추상화(Abstraction) 활용: 인터페이스나 추상 클래스를 사용하여 새로운 기능을 추가할 때 기존 코드의 변경을 최소화한다.
- 전략 패턴(Strategy Pattern): 실행할 알고리즘을 인터페이스로 분리하고, 필요에 따라 새로운 구현체를 추가하는 방식.
- 템플릿 메서드 패턴(Template Method Pattern): 상위 클래스에 공통 로직을 정의하고, 하위 클래스에서 특정 동작을 오버라이드하여 확장.
✅ OCP 적용 예제 (Java)
// OCP를 적용한 예제: 확장을 쉽게 하면서 기존 코드 변경을 최소화
interface DiscountPolicy {
double applyDiscount(double price);
}
// 기존 할인 정책
class PercentageDiscount implements DiscountPolicy {
private final double percentage;
public PercentageDiscount(double percentage) {
this.percentage = percentage;
}
@Override
public double applyDiscount(double price) {
return price * (1 - percentage / 100);
}
}
// 새로운 할인 정책 추가 (OCP 적용: 기존 코드를 변경하지 않음)
class FixedAmountDiscount implements DiscountPolicy {
private final double discountAmount;
public FixedAmountDiscount(double discountAmount) {
this.discountAmount = discountAmount;
}
@Override
public double applyDiscount(double price) {
return price - discountAmount;
}
}
// 할인 적용 클래스
class Order {
private final DiscountPolicy discountPolicy;
public Order(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
public double calculateFinalPrice(double price) {
return discountPolicy.applyDiscount(price);
}
}
// 사용 예
public class Main {
public static void main(String[] args) {
Order order1 = new Order(new PercentageDiscount(10)); // 10% 할인 적용
Order order2 = new Order(new FixedAmountDiscount(5000)); // 5000원 할인 적용
System.out.println(order1.calculateFinalPrice(10000)); // 9000.0
System.out.println(order2.calculateFinalPrice(10000)); // 5000.0
}
}
➡ 기존 코드(Order 클래스)는 변경되지 않고, 새로운 할인 정책을 추가하여 확장 가능(OCP 만족).
SRP(Single Responsibility Principle, 단일 책임 원칙)
**SRP(Single Responsibility Principle)**는 **"클래스는 하나의 책임만 가져야 한다"**는 원칙이다.
- 하나의 클래스가 여러 가지 역할을 담당하면 변경 사항이 많아지고 유지보수가 어려워진다.
- 하나의 책임만 가지도록 클래스를 분리하면 변경이 필요할 때 해당 기능만 수정하면 되므로 유지보수가 용이하다.
📌 SRP를 지키는 방법
- 하나의 클래스는 하나의 책임만 가지도록 분리한다.
- 단일 변경 이유(Single Reason to Change)를 가진다: 클래스가 변경되는 이유가 여러 개라면, 그만큼 역할이 많다는 뜻이므로 분리해야 한다.
- 높은 응집도(High Cohesion), 낮은 결합도(Low Coupling)를 유지한다.
❌ SRP를 위반한 코드 (나쁜 예)
class Employee {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
// 급여 계산 (비즈니스 로직)
public double calculatePay() {
return salary * 0.9; // 세금 공제 후 급여
}
// 급여 명세서 출력 (출력 관련 기능)
public void printPaySlip() {
System.out.println("Employee: " + name + ", Salary: " + calculatePay());
}
// 데이터 저장 (DB 관련 기능)
public void saveToDatabase() {
System.out.println("Saving employee data to database...");
}
}
➡ Employee 클래스는 급여 계산, 출력, DB 저장이라는 3가지 책임을 가지고 있어 SRP를 위반함.
✅ SRP 적용 예제 (좋은 예)
// 급여 계산 클래스 (비즈니스 로직)
class Payroll {
public double calculatePay(Employee employee) {
return employee.getSalary() * 0.9;
}
}
// 급여 명세서 출력 클래스 (출력 관련 책임)
class PaySlipPrinter {
public void printPaySlip(Employee employee, double salary) {
System.out.println("Employee: " + employee.getName() + ", Salary: " + salary);
}
}
// 데이터 저장 클래스 (DB 관련 책임)
class EmployeeRepository {
public void save(Employee employee) {
System.out.println("Saving employee data to database...");
}
}
// 사용 예
public class Main {
public static void main(String[] args) {
Employee emp = new Employee("John Doe", 5000);
Payroll payroll = new Payroll();
PaySlipPrinter printer = new PaySlipPrinter();
EmployeeRepository repository = new EmployeeRepository();
double salary = payroll.calculatePay(emp);
printer.printPaySlip(emp, salary);
repository.save(emp);
}
}
➡ Employee 클래스의 책임을 3개의 클래스로 분리하여 SRP를 만족.
✅ OCP & SRP의 차이점 정리
| 원칙 | 개념 | 목표 | 적용 방법 |
| OCP (개방-폐쇄 원칙) | 기존 코드를 변경하지 않고 확장 가능해야 함 | 유연성과 확장성을 높이고 유지보수성을 강화 | 인터페이스, 상속, 전략 패턴, 템플릿 메서드 패턴 활용 |
| SRP (단일 책임 원칙) | 클래스는 하나의 책임만 가져야 함 | 코드 응집도를 높이고, 변경에 유연하게 대응 | 역할을 분리하고 책임별 클래스를 나누기 |
둘 다 유지보수성과 확장성을 높이는 객체지향 설계 원칙으로, **OCP는 "변경 없이 확장", SRP는 "책임 분리"**에 초점을 맞춘다.
728x90