<Design Pattern>

디자인 패턴은 OOP에서 사용하는 개념으로, Object를 더 flexable하게 만듬으로써 "복잡한 구조"를 간단하게 만들고 / Object의 재사용성을 높이고 / 수정(유지보수)을 편리하게 해주는 효과가 있다


하지만 간단한 구조에서 남용하면 오히려 구조를 더 복잡하게 만드는 경향이 있다.

이 부분은 State Pattern을 보면서 이해해보도록 하자


<State Pattern의 필요성>

State Pattern이 언제 필요한지부터 살펴보자

"사람"이라는 Object가 있고,

이 Object는 아래와 같은 method들을 가지고 있다고 생각해보자

 - 밥 사먹기

 - 음료수 사먹기

 - PC방 가기

 - 찜질방 가기

 - 차에 기름넣기

그리고 마지막으로 "돈"이라는 멤버 데이터를 가지고 있다!

(편의상 가격은 없이, 돈이 있다(true)/없다(false)의 상태만 가진다고 가정한다)

이 모든 method들은 돈이 있거나/없는 "상태"에 따라 동작이 다르다

그리고 보통 이것은 조건문을 통해 구현된다


밥_사먹기()

{

....if no money:

........return;

....// code

}


조건문으로 구현하면 되는데, Design Pattern이 왜 필요한가?

그것은 우리의 method가 많기 때문이다

method가 많으면 무엇이 문제가 되느냐? 중복코드가 많아진다는 것이다

method 5개이므로 중복된 조건문도 5개가 들어간다

이때, "돈"이라는 상태 외에 "건강함"이라는 상태도 추가한다고 해보자

위 조건문이 아래와 같이 바뀌는 것으로.


if no money or no health:

....return;


조건문을 수정해야하는데, 5개의 중복코드가 있으므로 이 작업을 5번 해줘야 한다는 것이다

이것은 귀찮음과 실수를 유발할 수 있다

그런 이유에서, 중복코드를 제거하고자 State Pattern을 적용할 수 있다


<State pattern>

State라는 5개의 method가 선언된 interface가 있고, 그것을 구현한 EnabledState / UnabledState가 있다고 하자

State Pattern을 적용한 "사람"이라는 Object는 State라는 멤버를 추가로 가지게 된다

그리고 위 5개의 method들을 State에게 맡기는 것이다

현재 State가 EnabledState면, 밥사먹기 등이 성공적으로 동작할 것이고, 

UnabledState이면 "돈"이 없거나 "건강하지 않은" 상태인 것이므로 method들은 아무것도 하지 않을 것이다


코드를 첨부하지 않아서 설명이 추상적일 수 있다

코드 설명은 아래 글을 참조하자

http://secretroute.tistory.com/entry/Head-First-Design-Pattern-%EC%A0%9C10%EC%9E%A5-State-%ED%8C%A8%ED%84%B4


State Pattern을 사용함으로써 중복코드를 제거하고, 코드 수정을 더 편리하기 만들었다

이러한 효과는 모든 Design Pattern이 가지는 것이며, State Pattern을 설명하여 그것을 조금더 구체적으로 보였다


---


코드 추가하였음


<code example>

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
34
35
36
37
38
39
40
41
42
43
44
from abc import *
 
#################### context ####################
 
class Context:
    def __init__(self):
        self.idle = IdleState(self)
        self.sleep = SleepState(self)
        self.state = self.idle
    
    def sum(self, a, b):
        return self.state.sum(a, b)
    
    def wake_up(self):
        self.state = self.idle
        
#################### state ####################
 
class State:
    def __init__(self, context):
        self.context = context
    
    @abstractmethod
    def sum(self, a, b):
        pass
    
class IdleState(State):
    def sum(self, a, b):
        # set now_state <- sleep_state
        self.context.state = self.context.sleep
        return a+b
    
class SleepState(State):
    def sum(self, a, b):
        return None
 
#################### main ####################
    
if __name__ == '__main__':
    context = Context()
    print(context.sum(12)) # return 3 and set now_state <- sleep_state
    print(context.sum(34)) # None (sleep state)
    context.wake_up() # set now_state <- idle_state
    print(context.sum(56)) # return 11 and set now_state <- sleep_state
cs


<코드 설명>

context 클래스는 sum이라는 기능을 가지고있는데, 

idle state에서만 정상값을 리턴하며

값을 리턴하고나면 sleep state로 진입하게 되어있다


첫번째 context.sum()을 호출하면 idle state이므로 정상값을 리턴하고 sleep state로 바뀌게 된다

두번째 context.sum()을 호출하면 sleep state이므로 None이 리턴된다

context.wake_up()을 호출하여 idle state로 바꾼다

마지막 context.sum()을 호출하면 idle state이므로 정상값을 리턴하고 다시 sleep state로 바뀌게 된다


같은 메서드 콜이지만 context의 state에 따라 메서드 동작이 바뀌는 것을 확인할 수 있다

int값를 통해 state를 구현한다면 메서드 갯수에 비례하여 중복코드가 생기지만, state pattern은 그런 중복코드를 제거할 수 있다

'Language' 카테고리의 다른 글

[C] 2D 배열 포인터 example (Pointer to 2D array)  (0) 2017.12.18
[OOP] private 키워드의 필요성  (0) 2017.12.15
cmake 변수 설정방법  (0) 2017.12.07
cmake clean command  (0) 2017.12.06
[gcc option] linker option -Wl, -rpath, -L, -l  (0) 2017.12.06

WRITTEN BY
hojongs
블로그 옮겼습니다 https://hojongs.github.io/