디자인패턴1 - 스트래티지 패턴 (strategy pattern)
Strategy Pattern
스트래티지패턴은 객체의 동작/행위를 정의하고, 구현함으로써
해당 객체의 특정 동작/행위에 대한 구현을 행동객체(Behavior)에 위임하여
해당 객체와는 독립적으로 동작/행위를 구현하는 패턴이다.
적용할수 있는 예시를 들어보자!
게임을 개발함에 있어, 여러종류의 무기를 구현하자,
기본 무기엔 활, 총 ,검이 있다.
아래처럼 공통으로 가지는 동작을 추가한 Weapon 클래스를 상속받는 Gun,Bow, Sword를 구현하자.
하지만, 총과 활과 검의 공격방식은 서로 다르다.
그리고 또한, 앞으로 수많은 종류의 무기가 추가될예정이고,
총은 총알이 없어도, 총을 휘둘러 공격할수 있도록 업데이트예정이며,
또 검은 찌르기와, 베기 2가지 종류의 공격으로 나눌예정이다.
각각의 Attack 메소드를 오버라이딩해서 구현하는 방법도 있지만,
상속은 이러한 변화에 유연하지않아 각 업데이트에 대응하는데 힘들것이고,
또한 점점 재사용하기 힘든코드가 될것이다.
그럼 어떻게 구현해야할까?
먼저 Gun,Bow,Sword클래스의 Attack행위/동작에 대한 인터페이스를 정의한다.
interface AttackBehavior {
public void attack();
}
그리고 이 행위/동작에 대한 인터페이스를 구현하는 클래스를 생성하자
class GunShootAttack implements AttackBehavior{
public void attack() {
System.out.println("총 발사 ! ");
}
}
class ArrowShootAttack implements AttackBehavior{
public void attack() {
System.out.println("화살 발사 ! ");
}
}
class StabAttack implements AttackBehavior{
public void attack() {
System.out.println("찌르기 ! ");
}
}
class CutAttack implements AttackBehavior{
public void attack() {
System.out.println("베기 ! ");
}
}
class HitAttack implements AttackBehavior{
public void attack() {
System.out.println("때리기 !");
}
}
class NoAttack implements AttackBehavior{
public void attack() {
System.out.println("공격 불가");
}
}
총 발사 , 화살 발사, 찌르기, 뻬기, 때리기, 공격불가등의 행위에 대한 구현체(행동객체)를 선언하였고,
추가되는 공격종류에 대해서는 구현체를 만들면 된다.
무기객체에 Attack 행위를 행동객체에 위임해보자 .
필요에 따라서는 행동객체를 동적으로 할당할수 있다.
abstract class Weapon{
//행동객체
AttackBehavior attackBehavior;
public Weapon(AttackBehavior attackBehavior ){
setAttackBehavior(attackBehavior);
}
void setAttackBehavior(AttackBehavior attackBehavior){
this.attackBehavior=attackBehavior; //행위 동적할당
}
void attack(){
attackBehavior.attack(); //attack의 행위를 행동객체에 위임!
}
//부셔짐 - 동적으로 행동객체를 할당할수있다.
void breakDown() {
setAttackBehavior(new NoAttack());
}
}
구현이 다되었으면, 테스트를 해보자 .
public static void main(String[] args) {
Weapon weapon1 = new ShotGun();
weapon1.attack(); //빵야
weapon1.attack(); //빵야
//총알 다씀 - 동적으로 행동객체를 할당할수있다.
weapon1.setAttackBehavior(new HitAttack());
weapon1.attack(); //총으로 때리기!
Weapon weapon2 = new Bow();
weapon2.attack(); // 화살쏘기
weapon2.breakDown(); //고장
weapon2.attack(); //공격불가 .....
Weapon weapon3 = new Sword();
weapon3.attack(); //찌르기!
weapon3.setAttackBehavior(new CutAttack()); //베기로 변경
weapon3.attack(); //베기!
weapon3.setAttackBehavior(new StabAttack()); //찌르기로 변
weapon3.attack(); //찌르기!
}
무기객체의 특정 행동(Attack)을 인터페이스로 정의한 후,
무기 객체의 (Attack)행동에 대한 구현을 행동객체(Behavior)의 구현체에 위임하여
무기 객체와 독립적으로 Attack행위를 구현할수있었다.
※Attack과 같은 동작은 어떤객체의 알고리즘군이라고 표현된다.
이러한 알고리즘군을 정의하고, 각각을 캡슐화하여 교환해서 사용할수 있도록 만든다.
이러한 패턴으로 특정동작을 해야하는 객체와 독립적으로 알고리즘군을 구현할수 있다.
특정 동작이 객체에 영향을 받지 않고, 여러 방식으로 구현될수있다.
객체는 이런 특정동작을 행동(Behavior)객체에 위임하기 때문에, 독립적으로 사용될수있다.
소스코드 - 깃허브 Star는 큰도움이됩니다!
참고