[디자인 패턴] 전략(Strategy) 패턴

[원본 링크]

이 글은 예전에 세미나 할때 썼던 발표자료를 다시 재구성한 것이다.


전략 패턴은 인터페이스와 소유관계를 활용한 주요 패턴 중 하나다.

디자인패턴의 기본 원칙은 이렇다.
1.바뀌는 부분을 찾아내서 따로 분리(캡슐화)해야 한다.
2.단순 구현이 아닌 인터페이스에 맞춰 개발한다.
3.상속보다는 구성(소유관계)을 활용한다.


일단 코드를 보기에 앞서 시나리오를 보자
John은 학교 과제로 오리 시뮬레이션 프로그램을 만들게 되었다. 그는 객체지향 기법을 활용해 Duck이라는 부모 클래스를 두고 Duck을 확장해서 모든 종류의 오리를 만들었다.

무난하게 잘 짠듯 보인다.

근데 갑자기 교수가 저 오리 클래스에 전부 날아다니는 기능을 추가하라고 한다!!
그럼 어떻게 해야할까?
그래서 John은 그냥 추상클래스에 fly 메서드를 추가 구현했다.

근데 문제가 있다. 저중에서 고무오리는 상식적으로 날 수 없는데, 강제적으로 fly 메서드를 상속받아 날 수 있게 된 것이다!!

그래서 일단 John은 고무오리에 fly 메서드를 오버라이딩해서 아무것도 확인하지 않게 했다.
문제는 일단락된 듯하다.

하지만 이 방법도 문제가 있다.
여기서는 규모가 작아 대충 해결이 되긴 했지만, 고무오리같은 클래스가 많을 경우 하나씩 확인해서 다 고친다는건 꽤나 힘든 일이 될 것이다.

John은 이 문제를 깨닫고 인터페이스를 사용해보았다.
메서드를 전부 인터페이스로 분리해서 선택적으로 상속받아 구현하게 한 것이다.

그런데 이러면 구현이 너무 복잡해진다. 클래스마다 다 인터페이스 구현을 해줘야 하고, 코드 중복도 심각하다.
fly 구현의 공통적인 부분이 바뀌어야 한다면 구현한 코드를 하나하나 바꿔야 하는 것이다.

이제 정리하고 결론을 내보자.
여기서 바뀔 수 있는 부분은 fly와 quack라는 행동이다.
그럼 행동의 구현을 최대한 분리해서 재사용할 수 있도록 하면 되는 일이다.
행동의 기본 인터페이스를 두고 행동의 세부사항은 인터페이스를 상속받아 클래스로 구현. 그걸 각 오리 클래스가 소유하는 형태면 된다.

fly 인터페이스와 행동을 미리 구현하고

quack도 구현한다,

그리고 오리 추상 클래스에 이 행동 인터페이스를 멤버변수로 소유시킨다.
그러고 나서 오리들을 구현할 때는 특성에 맞춰서 구현된 행동 클래스들을 대입만 하면 되는 것이다.

이러면 코드의 중복을 방지하고 클래스의 재사용, 유지보수성을 극대화할 수 있다.
추가적인 행동이 필요하다면 그냥 클래스 새로 구현하고 대입하기만 하면 된다.

이게 바로 전략 패턴이다.


참조: 헤드퍼스트 디자인 패턴