💡 결합도
- 모듈(클래스, 패키지, etc) 사이 의존도를 나타내는 지표
- 강한 결합
- 어떤 클래스가 다른 클래스에 많이 의존하고 있는 구조
- 느슨한 결합
💡 책무
- 자신이 해야 하는 일
- 하지 않으면 안 되는 임무
8.1 결합도와 책무
단일 책임 원칙 (SRP)
클래스가 담당하는 책임은 하나로 제한해야 한다.
- 소프트웨어 책임
- 자신의 관심사와 관련해서 정상적으로 동작하도록 제어하는 것
- SRP를 지키도록 노력하는 방법 = 책임을 잘 고려해서 설계
- SRP를 지키면 느슨한 결합 구조
- 관심사에 따라 분리해서 독립되어 있는 구조
- 관련 사양이 변경되어도 서로 영향을 주지 않는 구조
DRY 원칙의 잘못된 적용
모든 지식은 시스템 내에서 단 한 번만, 애매하지 않고, 권위 있게 표현되어야 한다.
- 하지만!! → 같은 로직, 비슷한 로직이라도 개념이 다르면 중복을 허용해야 함
- 개념적으로 다른 것까지 무리하게 중복 제거 → 강한 결합 상태
- 비즈니스 지식
- 소프트웨어에서 다루는 비즈니스 개념
- 할인, 관심 상품, 크리스마스 캠페인 등등 모두 개념
- 일반 로직이 아님을 알게 된 순간 (개념이 다르다는 것을 알게 된 순간) 곧바로 일반화 했던 것을 나눠야 함
8.2 다양한 강한 결합 사례
상속 관련 강한 결합
- 상속은 주의깊게 다루지 않으면 강합 결합 유발
- 상속관계에서 서브 클래스는 슈퍼 클래스에 크게 의존
- 슈퍼 클래스는 서브 클래스 신경쓰지 않고 변경됨
- 변경 시 서로의 내용을 알아야 하는 상속 구조는 피하는 것이 좋음
- 상속보다
컴포지션 구조
-
사용하고 싶은 클래스를 private 인스턴스 변수로 갖고 시작하는 구조
-
서브 - 슈퍼 클래스가 서로 구조를 몰라도 되기 때문에 결합도가 줄어듬
-
PhysicalAttack 로직 변경되도 FighterPhysicalAttack 클래스는 영향을 적게 받음
class FighterPhysicalAttack {
private final PhysicalAttack physicalAttack;
int singleAttackDamage() {
return physicalAttack.singleAttackDamage() + 20;
}
int doubleAttackDamage() {
return physicalAttack.doubleAttackDamage() + 10;
}
}
- 상속보다
템플릿 메소드 패턴
- 상속 사용 시 고려할 사항
- SRP 원칙 준수 여부
- 값 객체 사용 가능한가?
- 컴포지션을 사용해볼까?
- 정 사용해야 한다면, 템플릿 메소드 패턴을 적용해볼까?
인스턴스 변수 별로 클래스 분할이 가능한 로직
- 클래스를 잘 분리하려면, 각 인스턴스 변수와 메소드가 무엇과 관련 있는지 잘 파악해야 함.
- 관련 있는 (인스턴스 - 메소드) 로 클래스를 분리하면 된다.
- Jig 같은 영향 스케치 도구를 이용해보는 것도 좋은 방법
특별한 이유없이 public 금지
- 접근지정자를 이용해서 모듈 간 불필요한 의존관계를 제거해야 한다.
public | 모든 클래스에서 접근 가능 |
---|
protected | 같은 클래스, 상속받은 클래스에서 접근 가능 |
(default) | 같은 패키지 내 클래스에서 접근 가능 |
private | 같은 클래스에서 접근 가능 |
- 패키지 안에서는 밀집한 클래스끼리 응집하게 설계
- 그래서 기본값이 package private인 것
private 메소드가 많다 = 클래스 책임이 많다
높은 응집도를 오해해서 생기는 강한 결합
- 자주 발생
- 각각의 개념을 잘 분리
- 결과적으로,
느슨한 결합 + 높은 응집도 설계
가 좋은 설계!
- 응집도 높이는 설계할 때 다른 개념이 섞이는 지 잘 판단
스마트 UI
- 화면 표시 담당 클래스 중에서 화면 표시와 직접 관련 없는 책무가 구현되어 있는 클래스
- 화면 표시 책무, 그렇지 않은 책무가 강하게 결합
거대 데이터 클래스
- 전역변수와 같은 성질
- 동기화로 인한 성능 저하 등 발생
트랜잭션 스크립트 패턴
- 메소드 내부에 일련 처리가 하나하나 길게 작성되어 있는 구조
- 데이터 클래스, 데이터 사용 클래스가 분리되어 있는 경우 자주 발생
갓 클래스
- 하나의 클래스 내부에 수천, 수만 로직 담아 책임이 막중한 클래스
8.3 강한 결합 클래스 대처법
- OOP 설계 준수 → SRP 준수
- 책임별로 클래스 분할
- 조기 리턴
- 전략 패턴
- 일급 컬렉션
- 목적 중심 이름 설계