목표
1. 컴포지션 사용 시점
객체 간의 관계를 “has-a” 관계로 표현하고 싶을 때
런타임에 객체의 동작을 변경하고 싶을 때
상속 대신 유연한 구조가 필요할 때
클래스 다이어그램 classDiagram
class WeaponBehavior {
<<interface>>
+useWeapon()
}
class Character {
#weaponBehavior: WeaponBehavior
+setWeaponBehavior(wb: WeaponBehavior)
+performWeapon()
+display()*
}
class Knight {
+display()
}
class Archer {
+display()
}
class SwordBehavior {
+useWeapon()
}
class BowBehavior {
+useWeapon()
}
WeaponBehavior <|.. SwordBehavior : implements
WeaponBehavior <|.. BowBehavior : implements
Character <|-- Knight : extends
Character <|-- Archer : extends
Character *-- WeaponBehavior : has
예시 코드 게임 캐릭터와 무기 시스템을 구현한 예시를 통해 컴포지션을 살펴보겠습니다.
1. 무기 행동 인터페이스 1 2 3 public interface WeaponBehavior { void useWeapon () ; }
2. 구체적인 무기 행동 구현 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class SwordBehavior implements WeaponBehavior { @Override public void useWeapon () { System.out.println("검으로 베기 공격!" ); } } public class BowBehavior implements WeaponBehavior { @Override public void useWeapon () { System.out.println("활로 화살 발사!" ); } }
3. 캐릭터 추상 클래스 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public abstract class Character { protected WeaponBehavior weaponBehavior; public void setWeaponBehavior (WeaponBehavior wb) { this .weaponBehavior = wb; } public void performWeapon () { if (weaponBehavior != null ) { weaponBehavior.useWeapon(); } else { System.out.println("무기가 없습니다!" ); } } public abstract void display () ; }
4. 구체적인 캐릭터 클래스 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class Knight extends Character { public Knight () { weaponBehavior = new SwordBehavior (); } @Override public void display () { System.out.println("나는 기사입니다!" ); } } public class Archer extends Character { public Archer () { weaponBehavior = new BowBehavior (); } @Override public void display () { System.out.println("나는 궁수입니다!" ); } }
5. 테스트 코드 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Game { public static void main (String[] args) { Character knight = new Knight (); knight.display(); knight.performWeapon(); Character archer = new Archer (); archer.display(); archer.performWeapon(); System.out.println("기사가 활로 무기를 교체합니다!" ); knight.setWeaponBehavior(new BowBehavior ()); knight.performWeapon(); System.out.println("궁수가 검으로 무기를 교체합니다!" ); archer.setWeaponBehavior(new SwordBehavior ()); archer.performWeapon(); } }
실행 결과 1 2 3 4 5 6 7 8 9 10 나는 기사입니다! 검으로 베기 공격! 나는 궁수입니다! 활로 화살 발사! 기사가 활로 무기를 교체합니다! 활로 화살 발사! 궁수가 검으로 무기를 교체합니다! 검으로 베기 공격!
컴포지션 장점
유연성: 런타임에 무기를 교체할 수 있습니다.
확장성: 새로운 무기나 캐릭터를 쉽게 추가할 수 있습니다.
재사용성: 무기 행동을 다른 클래스에서도 재사용할 수 있습니다.
캡슐화: 무기 관련 동작이 WeaponBehavior
인터페이스에 캡슐화되어 있습니다.
정리
컴포지션은 객체 간의 관계를 “has-a” 관계로 표현하고 싶을 때 사용합니다.
상속 대신 유연한 구조가 필요할 때 사용합니다.
런타임에 객체의 동작을 변경하고 싶을 때 사용합니다.
상속 대신 유연한 구조가 필요할 때 사용합니다.
ref