티스토리 뷰
안녕하세요, 제이입니다.
오늘은 디자인 패턴의 일종인 Strategy Pattern에 대해 정리 해 보겠습니다.
모든 Design Pattern 관련 포스팅은 아래 서적을 활용하여 직접 구현한 내용입니다.
정말 볼 때마다 초등학교 영어학원 서적을 생각나게 하는 디자인과 구성이 인상적인 헤드퍼스트 시리즈의 책을 활용하였습니다. 해당 서적은 JAVA로 구현되어 있지만, 저는 C++로 구현해 볼 예정입니다. 많이 부족한 개발자라, 언제나 지적은 환영합니다.
1. Strategy Pattern
간단하게 말해서 실행 중에 알고리즘을 고를 수 있는 패턴입니다.
가령 오리라는 객체가 있다고 합시다.
오리가 할 수 있는 일 1. 수영하기 2. 꽥꽥 울기 3. 뒤뚱뒤뚱 걸어다니기 4. 날아다니기 . . |
오리가 할 수 있는 일은 매우 많습니다.
이 할 수 있는 일을 가지고 오리라는 객체를 만들고, 상속을 받아 여러 종류의 오리를 표현하게 되면 여러 모로 효율적인 개발이 가능할겁니다. 이 오리 객체를 이용해서 여러 종류의 오리를 만들어 봅시다.
|
| ||
흰 오리 - 수영 가능 - 걷기 가능 - 울기 가능 - 날아다니기 가능 |
예쁜 오리 - 수영 가능 - 걷기 가능 - 울기 가능 - 날아다니기 가능 |
화려한 오리 - 수영 가능 - 걷기 가능 - 울기 가능 - 날아다니기 가능 |
러버덕 - 수영 가능 - 걷기 불가능 - 울기 불가능 - 날아다니기 불가능 |
다른 오리들은 위의 모든 기능이 가능하지만, 일종의 오리인 러버덕은 울 수도 없고, 날아다닐 수도, 걸어다닐 수도 없는 오리입니다. 주어진 자원으로 러버덕을 만들어 본다고 가정을 해 봅시다.
1) 상속으로 러버덕 구현하기
- 오버라이드를 통해 함수를 재정의하게 되면 울지도 않는, 날지도 않는, 걸어다닐 수도 없는 오리를 구현할 수 있다.
- 하지만 여러 오리의 행동을 정확하게 알기 어렵다.
- 게다가, 굳이 나는 기능, 꽥꽥거리는 기능, 걸어다니는 기능이 필요없는데 이러한 기능들을 상속받아야 할 필요가 있을까?
2) 인터페이스로 구현
- 굳이 필요없는 기능을 넣지 말자.
- 나는 기능, 우는 기능 등을 따로 인터페이스로 분리해서 구현.
나는 기능, 우는 기능을 인터페이스로 분리해서 구현하게 되면, 일일이 흰 오리, 예쁜 오리, 화려한 오리의 나는 기능을 일일이 구현해야 합니다. 이 세 오리의 나는 기능, 우는 기능은 같기 때문에, 결국 코드의 중복만 늘리는 꼴이 됩니다.
오리를 보면, 우리가 장난감 오리를 포함해서 오리라고 부르는 것들의 공통적인 특징이 있습니다(납작하고 긴 부리, 날개가 있음...). 모든 오리의 공통적인 기능은 변하지 않습니다. 달라질 리 없는 부분은 놔 두고, 여기서 달라질 수 있는 기능만 분리를 시켜, 그때 그때 해당하는 객체가 달라질 수 있는 기능을 바꿔 끼울 수 있게 하는 것이 바로 이 Strategy Pattern입니다.
바뀌는 부분을 따로 뽑아서 캡슐화를 시켜 바뀌지 않는 부분에는 영향을 미치지 않게 구현을 하면 됩니다.
2. 구현
- 바뀌지 않는 부분과 바뀌는 부분을 분리합니다. 저는 오리의 우는 행위와 나는 행위에 대해 분리를 하겠습니다. 클래스 다이어그램은 Visual Studio의 클래스 디자이너를 이용하였습니다.
- C++은 뚜렷하게 인터페이스의 개념이 있는 것이 아니기 때문에 추상클래스로 각 행위들을 정의하였습니다.
1) 오리의 우는 행위 (QuackBehavior)
러버덕은 울지 못하지만 다른 오리들은 울 수 있습니다. 그래서 오리의 우는 행위 인터페이스를 만들고, Quack! 하고 우는 행위, 그리고 조용한 울음을 추가하였습니다.
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 |
class QuackBehavior
{
public:
QuackBehavior();
~QuackBehavior();
virtual void Quack();
};
class QuackQuack : public QuackBehavior
{
public:
QuackQuack();
~QuackQuack();
void Quack();
};
class QuietDuck : public QuackBehavior
{
public:
QuietDuck();
~QuietDuck();
void Quack();
};
|
cs |
2) 오리의 나는 행위 (FlyBehavior)
오리 중에선 날 수 있는 오리도 있고, 날 수 없는 오리도 있습니다. 그래서 나는 행동 인터페이스를 정의하고, 그 밑에 나는 행위, 날지 않는 행위에 대해 정의해주었습니다.
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 |
class FlyBehavior
{
public:
FlyBehavior();
virtual ~FlyBehavior() = 0;
virtual void fly() = 0;
};
class FlyWithWing : public FlyBehavior
{
public:
FlyWithWing();
~FlyWithWing();
void fly();
};
class NotFly : public FlyBehavior
{
public:
NotFly();
~NotFly();
void fly();
};
|
cs |
3) 오리 구현
- 평범한 오리, 그리고 울 수도 없고 날 수도 없는 러버덕, 총 두 종류의 오리를 만들어 보겠습니다.
수퍼클래스의 오리는 나는 행위 (mFBehavior), 그리고 우는 행위 (mQBehavior), 총 두 가지의 클래스를 가지고 있습니다. 그리고 오리가 날 수 있도록 FlyDuck이라는 함수를 추가해주었고, 오리가 울 수 있도록 QuackDuck이라는 함수를 추가 해 주었습니다.
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
26
27
28
29
30
31
32
33 |
class Duck
{
public:
Duck();
~Duck();
QuackBehavior *mQBehavior;
FlyBehavior *mFBehavior;
void FlyDuck();
void QuackDuck();
};
class OrdinaryDuck : public Duck
{
public:
OrdinaryDuck()
{
mFBehavior = new FlyWithWing();
mQBehavior = new QuackQuack();
}
~OrdinaryDuck();
};
class RubberDuck : public Duck
{
public:
RubberDuck()
{
mQBehavior = new QuietDuck();
mFBehavior = new NotFly();
}
~RubberDuck();
};
|
cs |
그리고 메인에서 Duck 객체를 선언할 때, RubberDuck을 선언했다면 RubberDuck의 나는 행위, 우는 행위가 발생하고, OrdinaryDuck을 선언했다면 Quack 하는 오리와 날아다니는 오리를 볼 수 있을 것입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 |
int main()
{
Duck *duck = new OrdinaryDuck();
duck->FlyDuck();
duck->QuackDuck();
Duck *rubberDuck = new RubberDuck();
rubberDuck->FlyDuck();
rubberDuck->QuackDuck();
return 0;
} |
cs |
위의 main을 실행시켜 보면,
어떤 객체를 생성시켰는가에 따라 다른 오리의 행동이 발생하는 것을 확인할 수 있습니다.
처음 이야기 했던 상속을 사용한다면 나중에 유지보수를 할 때 시간이 많이 걸리게 되고, 모든 행위를 인터페이스만으로 표현했을 때 코드의 중복이 늘어나게 됩니다. 이 때 Strategy Pattern을 사용하게 되면 우는 행위를 고친다면 우는 행위만 신경쓰기 때문에 유지보수에 용이한 코드, 그리고 추후에 새로운 알고리즘의 추가가 용이해집니다.
'Design Pattern' 카테고리의 다른 글
디자인 패턴 - 7. Facade Pattern (0) | 2018.10.15 |
---|---|
디자인 패턴 - 6. Adapter Pattern (0) | 2018.10.12 |
디자인 패턴 - 5. Command Pattern (0) | 2018.10.09 |
디자인 패턴 - 4. Singleton Pattern (0) | 2018.10.08 |
디자인 패턴 - 2. Observer Pattern (1) | 2018.09.16 |