오봉이와 함께하는 개발 블로그
강한 결합 깨기 (상속 part) - 내 코드가 그렇게 이상한가요? 본문
강한 결합 - 상속
어설프게 사용하는 상속은 강한 결합 구조를 유도한다. 객체지향을 소개하는 많은 글에서 객체지향의 장점으로 상속을 소개하는 경우가 많은데 잘 사용하면 문제가 없겠지만, 어설프게 사용하면 오히려 독이 될 수 있는 방법이다.
그래서 상속 대신 사용하는 컴포지션을 사용하라는 말이 있다.
상속 문제 - 슈펴 클래스에 의존
먼저 상속의 문제를 알아보자
PhysicalAttack 클래스는 단일 공격과 두번 연속 공격하는 메서드가 존재한다. 해당 PhysicalAttack 클래스는 앞으로 존재할 모든 공격에 대해 부모 클래스로 설계한 클래스다.
public class PhysicalAttack {
public int singleAttackDamage() {
return 10;
}
public int doubleAttackDamage() {
return 20;
}
}
아래 클래스는 격투가 공격에 대한 클래스로 기본 PhysicalAttack를 상속 받아 구현한 클래스다.
public class FighterPhysicalAttack extends PhysicalAttack {
@Override
public int singleAttackDamage() {
return super.singleAttackDamage() + 20;
}
@Override
public int doubleAttackDamage() {
return super.doubleAttackDamage() + 10;
}
}
아래 클래스는 궁수 공격에 대한 클래스로 기본 PhysicalAttack를 상속 받아 구현한 클래스다.
public class HunterPhysicalAttack extends PhysicalAttack{
@Override
public int singleAttackDamage() {
return super.singleAttackDamage() + 25;
}
@Override
public int doubleAttackDamage() {
return super.doubleAttackDamage() + 15;
}
}
문제가 없을 거 같지만 이제 기본 PhysicalAttack를 수정하면 문제가 발생한다.
PhysicalAttack에서 doubleAttackDamage에서 20을 반환하는 것이 아니라 singleAttackDamage를 두번 실행 시키도록 수정하면 의도했던 동작이 나오지 않고 singleAttackDamage를 두번 실행한 결과에 특정 데미지가 추가되어 반환할 것이다.
public class PhysicalAttack {
public int singleAttackDamage() {
return 10;
}
public int doubleAttackDamage() {
return singleAttackDamage() + singleAttackDamage();
}
}
상속 관계에서 서브 클래스는 슈퍼 클래스에 크게 의존하는데, 보통은 슈퍼 클래스를 수정할 때 서브 클래스는 크게 생각하지 않고 바꾸는 경우가 있고 생각을 하더라도 논리적으로 오류가 발생할 수 있기 때문에 비용이 더 많이 발생하는 코드이다.
그럼 어떻게 해결하면 좋을까?
상속 문제 해결 방법 - 컴포지션 사용
상속 대신 사용하는 컴포지션을 사용하라
는 말이 있는데 코드로 확인하자.
public class FighterPhysicalAttack {
private final PhysicalAttack physicalAttack;
public FighterPhysicalAttack(PhysicalAttack physicalAttack) {
this.physicalAttack = physicalAttack;
}
public int singleAttackDamage() {
return physicalAttack.singleAttackDamage() + 20;
}
public int doubleAttackDamage() {
return physicalAttack.doubleAttackDamage() + 10;
}
}
이런 식으로 사용하면 우리가 처음에 의도했던 방식으로 코드가 구현된다.
컴포지션이란 사용하려 하는 클래스를 private 인스턴스 변수로 갖고 사용하는 것을 말한다.
컴포지션 구조를 사용하면 PhysicalAttack의 코드를 수정해도 FighterPhysicalAttack에 영향이 적어진다.
가능한 상속보단 컴포지션을 이용하자
'자바' 카테고리의 다른 글
Sync & Async / Blocking & Non-Blocking (0) | 2023.11.23 |
---|---|
상속의 나쁜 예 (강한 결합) - 내 코드가 그렇게 이상한가요? (0) | 2023.11.20 |
결합도와 책무 - 내 코드가 그렇게 이상한가요? (1) | 2023.11.14 |
성숙한 클래스 - 내 코드가 그렇게 이상한가요? (0) | 2023.11.12 |
Java - Reflection API (0) | 2022.11.26 |