클래스는 단 한개의 책임을 가져야 한다.
-> 클래스가 가진 여러 책임별로 변경 사항이 생길 수 있다.
-> 클래스가 하나의 책임을 가지면 변경되는 이유는 그 책임의 내용이 변경되어서 이다.
책임의 단위는 변화되는 부분과 관련이 있다.
Class의 변수/메소드를 사용하는 사용자(Class 외부)마다 다른 의미로 사용하거나(변수), 다른 메소드를 사용한다면 단일 책임에 원칙에 위배될 확률이 크다.
ex) Domain Class(model)가 정보 반환(getter), 정보 저장(save), 정보 출력(print)의 역할을 한다면,
정보 저장은 저장 매체에 따라서
SRP 원칙은 변수, 클래스, 패키지, 모듈, 데이터베이스 테이블가지 적용할 수 있는 원칙
두가지 알려진 방법
1) 클래스에서 변화가 있는 부분은 sub class로, 변화가 없는 부분(공통)은 super class로
2) 클래스 일부를 extract하여 멤버로
주변 변경에 닫혀 있다
한 클래스가 사용하는 다른 클래스의 인스턴스가 여러 종류일 때, 인스턴스마다 다른 사용법이 필요
자신의 확장
예제
변화하는 부분을 추상화(상위 클래스/인터페이스)하자
상위 타입이 풍부해야 하위 타입의 인스턴스를 상위형 참조 변수에 대입해 그 역할을 할 수 있다.
상위 타입이 풍부하지 않으면 형변환을 자주 해야됨
또는 if ( 하위 A instance of 상위) 같은 로직이 필요해져서 코드가 복잡해짐
예시
// ISP를 만족하지 않는다.
interface Printer {
copyDocument();
printDocument(document: Document);
stapleDocument(document: Document, tray: Number);
}
// 사용되지 않는 메서드를 구현하고 있다.
class SimplePrinter implements Printer {
public copyDocument() {} // 사용 하지 않음
public printDocument(document: Document) {
console.log("simple copy", document);
}
public stapleDocument(document: Document, tray: Number) {} // 사용 하지 않음
}
// ISP를 만족한다.
interface Printer {
printDocument(document: Document);
}
interface Stapler {
stapleDocument(document: Document, tray: number); }
interface Copier {
copyDocument();
}
class SimplePrinter implements Printer {
public printDocument(document: Document) {}
}
class SuperPrinter implements Printer, Stapler, Copier {
public copyDocument() {}
public printDocument(document: Document) {}
public stapleDocument(document: Document, tray: number) {}
}
자신보다 변하기 쉬운 것에 의존하던 것
-> 추상화된 인터페이스나 상위 클래스를 두어 변하기 쉬운 것의(구상체) 변화에 영향받지 않게 하는 것이 의존 역전 원칙이다.
User - Pay(추상체) - samsung/kakao/naver(구현체)
이게 다 유지보수를 잘 하려는 의도에서 생긴 원칙 같다!