java) 중복과 상속과 조합

띠용·2025년 4월 1일

우테코 7기 BE

목록 보기
3/14

코드 중복

장기 프로그램을 자바를 활용해 객체 지향적으로 구현한다고 생각해보자. 장(가운데 큰 녀석, 체스의 킹과 비슷하다)과 사(장 옆에 있는 두 기물들)를 각각의 객체로 구현하는 것은 자연스럽다. 그렇다면 장과 사의 이동 규칙을 정의할 필요가 있다. 그래서 Jang 클래스와 Sa 클래스를 각각 만들고 각각의 이동 규칙을 정의했다.

장(Jang)

  • 잡히면 게임이 끝난다.
  • 궁성 안에서만 이동이 가능하다.
  • 궁성 내부의 간선을 통해 상,하,좌,우,대각선(간선이 있는 경우) 1칸을 이동 할 수 있다.

사(Sa)

  • 궁성 안에서만 이동이 가능하다.
  • 궁성 내부의 간선을 통해 상,하,좌,우,대각선(간선이 있는 경우) 1칸을 이동 할 수 있다.

이렇게 각각의 이동 규칙을 정의하니 뭔가 불편하다.

게임 종료 여부나 기물 이름에서 분명한 차이가 존재하니 다른 객체로 나눠야 할 것 같긴 한데, 이동규칙과 관련된 많은 부분이 동일하다. 실제로 코드를 작성하게 된다면 먼저 작성한 클래스의 코드를 복붙해서 나머지 하나를 만들게 될 것이다. 코드 중복이 발생한다.

코드 중복을 왜 피해야 하나?

그냥 복붙해서 만들면 안될까? 안된다. 우리는 깔끔한 코드를 짜야한다. ClaenCode를 짜야한다. CleanCode를 위한 설계 원칙을 지켜야 한다. 왜나하면 개발자의 코드는 한 번 만들면 땡이 아니라 지속적으로 유지보수를 해야 하기 때문이다. 코드 중복은 중복 로직이 변경될 때마다 모든 변경부분을 찾아서 일일히 변경해줘야 하는 단점이 있다. CleanCode를 위한 DRY 원칙을 위배하게 되는 것이다.

그렇다면 이러한 중복 문제를 해결하기 위한 방법으로는 어떤 것이 있을까?
상속을 고려해볼 수 있다.

상속

상속을 사용하면 중복을 깔-끔하게 제거할 수 있다. 예를 들어 사를 먼저 구현하고 장이 사를 상속할 경우 (장 extends 사) 장에 구현해야 하는 코드는 "잡히면 게임이 끝난다." 하나로 줄어든다. 나머지는 자동으로 이미 사에 구현된 코드가 따라들어오게 된다.

아주 깔끔하고 좋다. 편안하다.

그런데 상속은 대부분의 경우에서 사용되지 않는다. 이렇게 강력하게 중복을 제거할 수 있는 상속을 왜 안쓸까?

너무 강력해서 그렇다. 상속은 부모 클래스와 자식 클래스 사이의 강결합을 초래한다. 부모 클래스의 변경에 자식 클래스가 직접적으로 영향을 받기 때문이다.

그렇다면 변경에도 유연하면서 중복도 줄일 수 있는 방법이 있을까? 이럴 때 조합을 고려해 볼 수 있다.

조합

조합은 슈퍼 클래스를 상속받는 대신 인스턴스 변수로 두고 사용하는 것을 말한다. 서브 클래스에서는 슈퍼 클래스의 인스턴스를 사용해 자신의 메서드를 정의할 수 있다. 약식으로 표현하면 아래와 같다.

class Jang {
	private Sa sa;
    
    public move() {
    	sa.move();
    }
    
    ...
}

이렇게 하면 Jang에는 move에 대한 코드의 중복을 없앨 수 있고, 만약 Sa의 move가 Jang과 달라진다면 sa.move를 사용하지 않으면 된다. 결합도를 낮춘 것이다. 이렇게 조합의 사용은 유지 보수에서 강점을 지닌다.

다만 이렇게 되면 결합도를 낮춘 만큼 Jang에도 move처럼 각각의 메서드를 정의해주긴 해야 한다.
내부 구현은 sa에서 가져다 쓰지만 시그니처 중복이 발생하게 되는 것이다.

나는 처음 상속을 사용하던 코드에서 주변 안티 상속파의 잔소리에 못 견뎌 조합으로 코드를 변경하던 중 열이 올랐다. 상속으로 깔끔하게 중복이 제거되었던 내 코드에 시그니처 중복이 쌓여가니 오기를 부렸던 것이다.

그렇게 결합 되는 게 싫으면 그냥 아예 떨어져. 중복 코드로 냅둬!

그래서 원상태로 확 돌려버릴까 싶었다.

웃기게도 머릿속에 아래와 같은 순환이 생겨버린 것이다.

그렇다면 이 순환 고리는 정말 맞는 것일까? 저 세 가지 상태는 각각의 장단점이 존재하여 트레이드 오프가 가능한 영역일까?

중복과 상속과 조합은 취향 차이인 것 일까?

결론

아니다. 이 글의 첫 문장에서도 알 수 있듯이 우리는 '객체 지향'을 해야 한다. 객체 지향을 하는 가장 큰 이유는 유지 보수의 편의를 위함이다. 따라서 중복 문제가 발생하면 유지 보수에서 가장 큰 이점을 가지는 조합을 우선적으로 고려하고, 절대적 상하관계가 존재하는(is-a 관계) 등의 특수한 상황에서 신중하게 상속을 고려해야 한다.

3개의 댓글

comment-user-thumbnail
2025년 4월 2일

빙글빙글 돌아가는 조상

답글 달기
comment-user-thumbnail
2025년 4월 2일

저와 띠용 폰트 셋이서 저 순환에서 3시간 동안 빠져나오지 못했던 기억이 나네요..

답글 달기
comment-user-thumbnail
2025년 4월 2일

띠용 따봉 띠용 따봉

답글 달기