💡 응집도란?
- 모듈 내부에 있는 데이터와 로직 사이 관계가 얼마나 강한지 나타내는 지표
- 응집도가 높을 수록 구조 변경, 유지보수 편리
static 메소드 오용
- static 메소드는 객체 생성하지 않고 사용 가능
- 데이터와 사용 로직이 멀리 떨어지게 될 가능성 존재
static 메소드는 인스턴스 변수 사용 불가
- 인스턴스 변수 사용이 불가하기 때문에 근본적으로 응집도가 낮을 수 밖에 없음
인스턴스 변수를 사용하는 구조로 변경
- 같은 기능을 하는 인스턴스 사용 구조로 변경하는 것이 응집도를 높이는 길
인스턴스 메소드인 척 하는 static 메소드
- add 메소드는 인스턴스 변수를 이용하지 않으므로, static 메소드
class PaymentManager {
private int discountRate;
int add(int amoun1, int amoun2) {
return amount1 + amount2;
}
}
static 메소드 사용 이유
- 절차지향 프로그래밍 잔재
- 간단하게 사용 가능하긴 함
- 응집도가 낮아지는 원흉
static 메소드는 언제 사용할까?
- 응집도 영향을 받지 않는 경우
- 횡단 관심사
- 로그 출력
- 포맷 변환
- 팩토리 메소드
초기화 로직 분산
- public 생성자의 경우 여러 곳에서 사용 가능함 → 응집도 떡락
- 의도하지 않는 초기화 발생 가능 → 더 떡락
private 생성자 + 팩토리 메소드
생성 로직이 너무 많아지면 → 팩토리 클래스
범용처리 클래스 (Common, Util)
- 너무 많은 로직이 한 클래스에 모이는 문제
- 관련성이 적은 로직이 범용 클래스에 모이게 됨.
- 객체 지향 설계 기본으로 돌아가기
- 횡단 관심사에는 써도 됨
- 로그 출력
- 오류 확인
- 디버깅
- 예외 처리
- 캐시
- 동기화
- 분산 처리
결과 리턴에 매개변수 사용 말기
- 매개변수를 출력으로 사용하면 안 된다.
- 반드시 인스턴스 변수나 지역변수를 메소드의 리턴값으로 사용해야 함.
class ActorManager {
void shift(Location location, int shiftX, int shiftY) {
location.x += shiftX;
location.y += shiftY;
}
}
class Location {
final int x;
final int y;
Location(final int x, final int y) {
this.x = x; this.y = y;
}
Location shift(final int shiftX, final int shiftY) {
final int nextX = x + shiftX;
final int nextY = y + shiftY;
return new Location(nextX, nextY);
}
}
매개변수 너무 많은 경우
- 매개변수가 너무 많으면 응집도 낮아짐
- 매개변수가 많으면 기능이 너무 많은지 의심
기본자료형에 대한 집착
- 기본자료형만으로 ‘돌아가기는 하는 프로그램’을 만들면 응집도 문제가 발생
의미 있는 단위는 모두 클래스로 만들기
- 개념적으로 의미 있는 단위로 클래스 만들어 응집도 챙기기
- 클래스를 매개변수로 넘길 수 있게 되므로, 매개변수 증식 문제를 해결 가능
메소드 체인
- 전역변수보다 악질
- 디미터 원칙
- 묻지 말고 명령하기
- 다른 객체 내부 상태 기반으로 판단, 제어 X
- 메소드로 명령해서 객체가 알아서 판단, 제어 O