* 클래스는 하나의 기능만 가지며, 어떤 변화에 의해 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 한다.
* SRP 책임이 분명해지기 때문에, 변경에 의한 연쇄 작용에서 자유로워질 수 있다.
* 가독성 향상과 유지보수가 용이해진다.
* 실전에서는 쉽지 않지만 늘 상기해야 한다.
* 변경을 위한 비용은 가능한 줄이고, 확장을 위한 비용은 가능한 극대화 해야 한다.
* 요구사항의 변경이나 추가사항이 발생하더라도, 기존 구성요소에는 수정이 일어나지 않고, 기존 구성 요소를 쉽게 확장해서 재사용한다.
* 객체지향의 추상화와 다형성을 활용한다.
* 서브 타입은 기반 타입이 약속한 규약(접근제한자, 예외 포함)을 지켜야 함.
* 클래스 상속, 인터페이스 상속을 이용해 확장성을 휙득한다.
* 다형성과 확장성을 극대화하기 위해 인터페이스를 사용하는 것이 더 좋다.
* 합성(composition)을 이용할 수도 있다.
* 가능한 최소한의 인터페이스만 구현한다.
* 만약 어떤 클래스를 이용하는 클라이언트가 여러 개고, 이들이 클래스의 특정 부분만 이용한다면, 여러 인터페이스로 분류하여 클라이언트가 필요한 기능만 전달한다.
* SRP 클래스의 단일 책임이라면, ISP는 인터페이스의 단일 책임
하위 모델의 변경이 상위 모듈의 변경을 요구하는 위계관계를 끊는다.
실제 사용관계는 그대로이지만, 추상화를 매개로 메세지를 주고 받으면서 관계를 느슨하게 만든다.
public Money calculatePay(Employee e) throws InvalidEmployeeType{
siwth (e.type){
case COMMSSIONED :
return calculateCommissionedPay(e);
case HOURLY :
return calculateHourlyPay(e);
case SALARIED :
return calculateSalariedPay(e);
default :
throw new InvalidEmployeeType(e.type);
}
}
public abstract class Employee{
public abstract boolean isPayday();
public abstract Money calculatePay();
public abstract void deliverPay(Money pay);
}
public interface EmployeeFactory{
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
}
public class EmployeeFactoryImple implements EmployeeFactory {
public Employee make Employee(EmployeeRecord r) throws InvalidEmployeeType{
siwth (r.type){
case COMMSSIONED :
return CommissionedEmployee(r);
case HOURLY :
return HourlyEmployee(r);
case SALARIED :
return SalariedEmployee(r);
default :
throw new InvalidEmployeeType(r.type);
}
}
계산과 타입 관리를 분리
타입에 대한 처리는 최대한 factory 에서만
// 객체를 인자로 넘기기
Circle makeCirlce(double x, double y, double radius) X
Circle makeCirlce(Point center double radius) O
// 가변 인자를 넘기기 (특별한 경우가 아니면 잘 사용하지 않음
String.format(String format, Object ... args);
함수와 관계없는 외부 상태를 변경 시킨다.