전략패턴은 변할 가능성이 있는 행동들(알고리즘군) 을 정의하고, 이를 캡슐화 시켜 각각의 행동들(알고리즘군)을 변경 및 수정해서 쓸 수 있게 해는 디자인 패턴이다. 해당패턴을 통해 클라이언트로부터 알고리즘(행동)을 분리해서 독립적으로 변경할 수 있다. (OCP, SRP)
기존
아래 코드의 Marin 는 직접적으로 attack() 을 구현하고 있다. 하지만 이 때, Marin 의 공격방법을 저격으로 바꿔야한다는 고객의 요구사항이 들어왔다. 물론 Marin 의 attack 을 직접적으로 수정할순 있지만 기존의 코드(hightlight 된 코드부분) 를 변경해야한다. 헌데 이는 OCP 에 위배되기 때문에 따라서 더 좋은 방법을 생각해야만 한다.
개선
달라지는 부분을 찾아 분리한다
우선 애플리케이션에서 달라지지 않는 부분과 달라지는 부분을 분리하여, 달라지는 부분들을 묶어 캡슐화 시킨다. 이를 통해 나중에 바뀌지 않는 부분에서 영향을 미치지 않고, 그 부분만 고치거나 확장할 수 있다 (OCP). 현재 우리의 앱에서 변할 수 있는 부분은 Attack 행동이다.
디자인 원칙 달라지는 부분을 찾아내고, 달라지지 않는 부분과 분리한다.
애플리케이션에서 달라지는 부분을 찾아내고, 달라지지 않는 부분과 분리하여 그 부분들을 묶어 캡슐화시킨다.
Attack 에 대한 행동들을 분리시켜 이들을 캡슐화할때 interface 를 이용한다.
디자인 원칙 : 구현보다는 인터페이스에 맞춰서 프로그래밍한다.
상위 형식에 맞춰 다형성을 활용하며 프로그래밍 한다는 의미이다.
두 클래스를 통합한다
상속보다는 포함(Composition) 을 활용하여 두 객체를 통합한다. 두 객체는 Solider 와 행동을 담당하는 AttackStrategy 이다. 이렇게 두 클래스를 합쳐 Soldier 에 행동을 할당할 수 있게 만들고, Soldier 에게 AttackStrategy 의 호출을 위임시킨다.
디자인 원칙 : 상속보다는 구성을 활용한다.
상속(A 는 B 이다) 보다 포함(A 에는 B가 있다) 이 나을 수 있다.
동적으로 행동을 지정할 수 있게 한다
setter 를 통해 행동을 동적으로 변경할 수 있도록 경로를 뚫어준다. 이를 통해 Soldier 를 확장하는 클래스들은 AttackStrategy 와 MoveStrategy 를 유동적으로 변경할 수 있다.
개선 확인
Soldier 를 확장한 Marin 은 자동으로 GunStrategy 와 MoveRoadStrategy 의 행동을 갖고 있게 된다.
Soldier 를 확장한 Sniper 는 setter 를 통해 기존 행동을 MoveRoadStrategy 와 SniperStrategy 로 설정해준다.
이제 기존 코드 변경없이 Marin 의 행동 을 동적으로 변경할 수 있게 되었다.
정리
전략패턴을 사용하면 변할 수 있는 행동 및 행위들이 인터페이스를 통해 관리되므로, 애플리케이션의 로직이 변경되도 기존의 코드는 고치지 않고 확장하거나 문제가 되는 부분을 수정할 수 있다.