Notice
Recent Posts
Recent Comments
Link
Today
Total
관리 메뉴

woodi

State Pattern 본문

Design Pattern

State Pattern

sungwoo jang 2023. 5. 9. 23:16

이번 포스팅에서는 디자인 패턴 중 상태를 관리할 때 적합한 State Pattern을 소개하고자한다.

 

개요

많은 프로그램에서 요구사항을 구현할 때 상태를 정의하여 관리하는 경우는 흔히 존재한다. 주로 조건문으로 분기를 나누어서 관리를 하며 각 상태에 따라 동작을 수행하고 다음상태로 변경하고 다시 이전으로 돌아가야할때도 있다.

 

그러나 프로젝트를 진행하면서 클라이언트의 요구사항으로 인해 상태를 추가해야하는 경우도 빈번하게 발생한다. 혼자서 작성한 코드인경우에는 금방 로직이 파악이되서 작업이 간단한 경우도 있지만 팀 워크를 하여 프로젝트를 진행할 때는 코드의 로직을 우선적으로 이해해야할 때가 많다. 조건문으로 상태를 분기로 나누어 관리를 하고있는정도는 금방 파악할 수 있지만 조건문 내에 다중 if 문으로 코드를 해석하는데 많은 시간을 소요하게 된다. 그러므로 누구든지 코드를 처음보아도 금방 해석이 가능하도록 가독성이 높은 코드를 작성해야한다. 

 

많은 디자인 패턴에서도 적용되듯이 State Pattern 에서도 관심사 분리를 하여 코드를 작성한다. 각 상태를 클래스로 나누고 공통적인 코드는 추상클래스를 통해 구현하며 각 상태마다의 동작은 클래스 내에서만 작성을 하여 관리를 수월하게 한다. 

그렇다면 어떠한 문제점이 있을 때 적용을 해야하는지 자세히 알아보도록 하자.

문제점 발견

아래와 같이 if 문으로 상태를 판단하고 그 상태에 대한 처리를 수행하는 코드를 작성해 보았을것이다.
적은 수의 상태를 사용하는 경우에는 문제가 되지 않지만 추가되는 요구사항에 의해 상태가 점점 더 많아지고 처리내용이 복잡해진다면 가독성이 떨어지게 될 것이고 유지보수도 어려워지게 될 것이다. 상태가 추가될 것이 어느정도 예상된다면 State Pattern 적용을 권장한다.

 

어떤경우에 상태패턴을 도입해야하는지 예제로 이해해보자

// 개선이 필요한 코드
fun execute(var state){
    if "peace":
        break
    if "test":
    	startTest()
        break
    if "result":
    	state = "peace"
        break
}

위 코드의 문제점이 무엇인가?

- 상태의 수 다수 존재

- 빈번한 상태별 코드 및 상태 변경

- 조건문에 클래스 필드의 변경이 잦음

- 유사한 상태들의 중복코드가 다수존재

 

개선되면 어떠한 장점이 있는가?

- 새로운 상태 추가 및 기존상태 독립적으로 유지관리 수월

- 조건문내의 각 상태들의 동작을 메서드로 분리하여 관리 가능

- 상태클래스들의 구조파악용이

- 중복코드는 추상클래스로 추출하여 제거 가능

- 기존 상태 또는 구조변경 없이 상태 추가 가능

 

 

 그렇다면 상태패턴으로 개선된 코드를 작성해보자.

class State:
    def __init__(self) -> None:
        pass
        
    def execute(self):
        pass
class Context:
    def __init__(self,state) -> None:
        self.state = PeaceState(self)
        pass
    
    def changeState(self, state):
        self.state = state
        pass

    def execute(self):
        self.state.execute()
    
    def startTest(self):
    	# UI 변경 동작 구현
    
    def stopTest(self):
    	# UI 변경 동작 구현
    
    def showResult(self):
    	# UI 변경 동작 구현
        
    def relaseResult(self):
    	# UI 변경 동작 구현

 

class PeaceState(State):
	def __init__(self,context) -> None:
        self.context = context
        pass
        
    def execute(self):
    	self.context.peace()
        pass
        
class TestState(State):
	def __init__(self,context) -> None:
        self.context = context
        pass
        
    def execute(self):
    	self.context.update()
        pass
        
    def next(self):
    	pass
        
class ResultState(State):
	def __init__(self,context) -> None:
        self.context = context
        pass
        
    def execute(self):
    	self.context.showResult()
        pass
        
    def next(self):
    	self.context.releaseResult()
    	pass

def main():
    print("main start")
    manager = Manager(ResultState())
    manager.execute()
    manager = Manager(PeaceState())
    manager.execute()
    pass

if __name__ == "__main__":
	main()

 

개선된 코드를 작성해보니 상태가 변경되면 해당 상태클래스내에서만 코드를 신경쓰면되므로 훨씬 가독성이 좋아졌다.

좀 더 복잡해진 상태가 있는경우 이 State 패턴을 도입해보길 바란다.

반응형