💡 클래스는 단 한 개의 책임을 가져야 한다.
💡 확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다.
이 말은 다음과 같다
앞선 장에서의 FlowController / ByteSource 예시는 개방 폐쇄 원칙을 지킨다
개방 폐쇄 원칙을 구현하는 방법
public class ResponseSender {
...
public void send() {
sendHeader();
sendBody();
}
protected void sendHeader() {
// 헤더 데이터 전송
}
protected void sendBody() {
// 텍스트로 데이터 전송
}
}
public class ZippedResponseSender extends ResponseSender {
public ZippedResponseSender(Data data) {
super(data);
}
@Overide
protected void sendBody() {
// 데이터 압축 처리
}
}
ZippedResponseSender 클래스로 기존 기능에 압축 기능을 추가하면서, ResponseSender의 클래스 코드는 바뀌지 않았다.instanceof
와 같은 타입 확인 연산자가 사용된다면 해당 코드는 개방 폐쇄 원칙을 지키지 않을 가능성이 높다💡 상위 타입의 객체를 하위 타입의 객체로 치환해도 상위 타입을 사용하는 프로그램은 정상적으로 동작해야 한다
public void someMethod(SuperClass sc) {
sc.someMethod();
}
...
someMethod( new SubClass() );
이 때, someMethod는 상위 타입인 SuperClass 타입의 객체를 사용하는데, 하위 타입 SubClass 객체를 전달해도 someMethod()가 정상적으로 동작해야한다.
public void increaseHeight(Rectangle rec) {
if (rec instanceof Square)
throw new CantSupportSquareException();
if (rec.getHeight() <= rec.getWidth()) {
rec.setHeight(rec.getWidth() + 10);
}
}
💡 인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리해야 한다.
즉, 클라이언트는 자신이 사용하는 메서드에만 의존해야 한다.
💡 고수준 모듈은 저수준 모듈의 구현에 의존해서는 안 된다.
저수준 모듈이 고수준 모듈에서 정의한 추상 타입에 의존해야 한다.