코드를 뚝딱뚝딱 만지다 보면 우리는 종종 특정 분류에 있는 값을 정의하여 사용해야 할 경우가 생기고
우리는 이것을 상수로 정의하여 사용하곤 합니다
가위바위보 게임을 예로 들자면
가위, 바위, 보 이 세 가지는 가위바위보라는 범위 내의 각각의 상수값으로 정의할 수 있습니다
public enum RPS {
ROCK,
PAPER,
SCISSORS;
}
모두가 아시다시피 가위바위보 게임은 가위,바위.보를 정의하는 것으로 끝나지 않습니다
가장 중요한 가위, 바위, 보 각각의 상관관계
가위는 보를 이긴다
보는 주먹을 이긴다
주먹은 가위를 이긴다
위 규칙에 대한 정의 혹은 행위가 필요합니다
위 규칙을 구현하기 위해 우리는 가위바위보의 규칙을 정의하는 Util Class를 정의할 수 있습니다.
public class RPSRule {
private RPSRule() {
throw new IllegalStateException();
}
public static RPS determineWinner(RPS first, RPS second) {
return switch (first) {
case ROCK -> PAPER == second ? second : first;
case SCISSORS -> ROCK == second ? second : first;
case PAPER -> SCISSORS == second ? second : first;
};
}
}
위에서 예시로 정의한 RPSRule 유틸 클래스의 determineWinner 메서드를 사용하면
두 가지 가위바위보 입력이 있을 때, 게임에서 승리한 값을 응답받을 수 있습니다
위 코드는 언뜻보면 그럴싸한 코드로 보일 수도 있습니다
하지만 위 코드를 OOP(Object Oriented Programing)의 관점에서 바라보면
RPS라는 객체(상수)는 내부에 값을 정의하고 있지만
값들의 연관관계 혹은 행위에 대한 정의를 RPSRule에 의존하고 있기에
이는 객체 내부 응집도가 떨어지는 코드라고 할 수 있습니다
이와 같은 상황에서 상수 내부에 행위를 정의함으로써 객체 내부 응집도를 높일 수 있는 방법 중 한 가지가 바로
Constant Specific Method Implementation 을 사용하는 것입니다
이는 상수에 추상메서드를 정의하고, 각각의 값에서 해당 추상 메서드를 구현하게 하면서, 행위를 정의할 수 있는 방법입니다
Constant Specific Method Implementation 을 사용하여 위 코드의 가위바위보 규칙을 RPS 내부에 정의한 내용은 다음과 같습니다
public enum RPS {
ROCK {
@Override
public RPS determineWinner(RPS other) {
// 상대가 PAPER 라면 상대 승
return other == PAPER ? PAPER : this;
}
},
PAPER {
@Override
public RPS determineWinner(RPS other) {
//상대가 SCISSORS 라면 상대 승
return other == SCISSORS ? SCISSORS : this;
}
},
SCISSORS {
@Override
public RPS determineWinner(RPS other) {
//상대가 ROCK 이라면 상대 승
return other == ROCK ? ROCK : this;
}
};
public abstract RPS determineWinner(RPSAct other);
}
위 코드에서처럼, 승리 값을 정하는 determineWinner 라는 메서드를 추상 메서드로 선언 후
각각의 값에서 행위를 구현할 수 있게 되었고, 응집도 높은 코드로 개선되었습니다
물론, 객체 지향과는 성격이 다른 패러다임인 DOP(Data Oriented Programing)의 관점에서 앞선 코드를 바라본다면
객체의 데이터와 행위를 분리한 것에서 잘 짜여진 코드라고 볼 수도 있습니다
따라서 앞선 코드가 잘못 구현 된 코드고, 뒤에 설명한 코드가 잘 짜여진 코드라고 섣부르게 판단하기 보단
주어진 상황과 코드 스타일에 따라 적절히 판단하여 사용하는 것이 중요합니다
'개발 > Java' 카테고리의 다른 글
[JPA] Jakarta Spec(JSR 338) - (2)기본 키(PK) 및 Entity ID (0) | 2023.08.23 |
---|---|
[JPA] Jakarta Spec(JSR 338) - (1)Entity, Field, Access Type (0) | 2023.08.17 |
[Java] 인수값 유효성 검증 - 표현 계층 vs 응용 계층 (0) | 2022.10.23 |
원시 값 포장 [Java] (2) | 2022.04.27 |
일급 컬렉션 사용하기 [Java] (0) | 2022.04.22 |
댓글