High Cohesion, Loose Coupling의 고전 원칙을 객체 지향의 관점에서 재정립한 것
“어떤 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 한다.”
😮 [클래스가 SRP를 지키지 못하는 경우]
💭 남자 클래스에 온갖 메서드를 때려넣어서 만들지 말고,
남자친구 클래스, 아들 클래스, 사원 클래스, 소대원 클래스로 역할(책임) 분리.
😮 [속성이 SRP를 지키지 못하는 경우]
💭 사람 클래스에 공통되지 않는 속성(군번)을 때려넣어서 만들지 말고,
남자 클래스, 여자 클래스로 분리해 차이점 각각 구현.
공통점은 사람 클래스를 상위 클래스로 두어 구현.
DB 테이블 설계할때 정규화와 비슷… 테이블/필드에 대한 SRP의 적용임~
😮 [메서드가 SRP를 지키지 못하는 경우]
💭 if 강아지가 수컷 { } else { } 처럼 메서드에서 분기처리를 하게 하지 말고,
강아지 추상 클래스에 해당 메서드를 명시한 후 수컷강아지 클래스와 암컷강아지 클래스에서 각각 그 기능에 맞게 메서드를 구현.
객체지향의 4대 특성 중 추상화와 가장 관계가 깊다!
애플리케이션 경계를 설정하고, 추상화를 통해 클래스를 선별하고 속성과 메서드를 설계할 때 SRP를 반드시 고려하자
“소프트웨어 엔티티(클래스, 모듈, 함수 등)는 확장에 대해서는 열려있어야 하지만, 변경에 대해서는 닫혀있어야 한다.”
“자신의 확장에는 열려있고, 주변의 변화에 대해서는 닫혀있어햐 한다.”
💭 운전자가 수동기어 자동차를 운전하다가 수동기어 자동차로 차를 바꿈
→ 상위 클래스 또는 인터페이스를 중간에 두어 운전자가 운전에 영향을 받지 않도록 하자. 다양한 자동차가 생긴다고 하더라도!
자동차 입장에서는 자신의 확장에는 개방되어 있고, 운전자 입장에서는 주변의 변화에 폐쇄돼 있다!
💭 JDBC를 사용하면 DB를 오라클에서 MySQL로 바꿔도 Connection 코드만 바꾸면 된다. 자바 애플리케이션은 주변의 변화에 닫혀있고, DB는 자신의 확장에 열려있다!
💭 자바는 개발자가 소스코드의 구동환경이 윈도우일지 리눅스일지 걱정할 필요가 없다. 각 운영체제별 JVM과 목적파일이 있다. 소스코드는 운영체제의 변화에 닫혀있고, 운영체제별 JVM은 확장에 열려있다!
OCP를 따르지 않는다면 객체지향 프로그래밍의 가장 큰 장점인 유연성, 재사용성, 유지보수성 등을 얻을 수 없다..
“서브 타입은 언제나 자신의 기반 타입(base type)으로 교체할 수 있어햐 한다.”
“하위클래스의 인스턴스는 상위형 객체 참조 변수에 대입해 상위 클래스의 인스턴스 역할을 하는 데 문제가 없어야 한다.”
상속의 두 조건인
그러나 상속이 조직도/계층도 형태로 구축된 경우는 X!! (분류도 : O)
💭 Dad 춘향이 = new Daughter();
→ 춘향이는 Dad형 객체 참조 변수이므로 아버지 역할을 할 수 있어야…
💭 Animal 뽀로로 = new Penguin();
→ 뽀로로가 Animal의 행위(메서드)를 하는데에 이상함 전혀 없음!
“클라이언트는 자신의 사용하지 않는 메서드에 의존 관계를 맺으면 안된다.”
SRP 대신에 사용할 수 있는 해결책!
그치만 SRP가 더 좋긴함…
상위클래스가 풍성할수록 좋다!
불필요한 형변환이 사라진다.
인터페이스는 작을수록 좋다!
해당 역할에만 충실하게, 최소한의 기능만 가져야 한다.
“고차원 모듈은 저차원 모듈에 의존하면 안된다. 이 두 모듈 모두 다른 추상화된 것에 의존해야 한다.”
“추상화된 것은 구체적인 것에 의존하면 안된다. 구체적인 것이 추상화된 것에 의존해야 한다.”
“자주 변경되는 구체(Concrete) 클래스에 의존하지 마라.”
“자신보다 변하기 쉬운 것에 의존하지 마라.”
💭 자동차가 스노우타이어에 의존한다면 스노우타이어를 일반타이어로 교체할 때 자동차는 그 영향에 노출되어 있음.
→ 자동차가 ‘스노우타이어’가 아닌, 추상화된 타이어 인터페이스에만 의존하게 하자(일반타이어, 스노우타이어, 광폭타이어 등이 구현).
스노우타이어는 이제 타이어 인터페이스에 의존하게 되어 의존 방향이 역전됨.
자신보다 변하기 쉬운 것에 의존하던 것을, 추상화된 인터페이스나 상위클래스를 두어 변하기 쉬운 것의 변화에 영향을 받지 않게 하는 것!
관심이 같은 것끼리는 하나의 객체 안으로, 또는 친한 객체로 모으고,
관심이 다른 것은 가능한 따로 떨어트려 서로 영향을 주지 않도록 분리하라.
관심사가 다르고, 변화의 시기가 다르면 분리해야 한다.
하나의 속성, 하나의 메서드, 하나의 클래스, 하나의 모듈, 하나의 패키지에는 하나의 관심사만 들어 있어야 한다.