As i wish

[Design pattern] State pattern (스테이트 패턴, 상태 패턴) 본문

Design Pattern

[Design pattern] State pattern (스테이트 패턴, 상태 패턴)

어면태 2019. 5. 31. 17:27

오늘은 스테이트 패턴 에 대하여 포스팅 해보겠습니다.

스테이트 패턴
객체의 내부 상태과 바뀜에 따라서 객체의 행동을 바꿀 수 있다. 마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있다.

 

일단, 결론부터 얘기하자면 스테이트 패턴은 if, switch 문을 캡슐화, 분리해서 변경하여 사용 할 수 있게 됩니다.

먼저 책에서 얘기한 예제를 들어서 설명해 보겠습니다.

뽑기에 대하여 예를 들었는데요. 

상태

동전이 있는 상태
동전이 없는 상태
알맹이 판매 상태
알맹이 매진 상태

행동

동전 투입
동전 반환
손잡이 돌림
알맹이 내보내기 (알맹이 매진 상태 또는 동전이 없는 상태 로 변경)

위 처럼 사용자에 행동에 따라서 상태를 변경 시켜줘야 하는데요. 이때 보통 대부분 If문을 사용하여 아래처럼 코드를 구성 하는데, 사실 if문의 길이가 길어지면 (switch 문도 동일) 상당히 관리하기 어려워지고 유지보수도 어려워 집니다. 그래서 '상태 패턴'을 사용하여 이를 해결 할 수 있게 해주죠.

if (상태 === 동전이 있는 상태) {
   ...
} else if (상태 === 동전이 없는 상태) {
  ...
}

 

 

이렇게 상태 (State) 들을 Context에 정의하고 상태가 바뀔 때 마다 Context 객체에서 상태를 변경해주면 됩니다. 그럼 Client 에서 객체가 바뀌는 듯한 효과를 얻을 수 있고 If 문 이나 Switch 문같이 조건문도 필요 없이 상태 객체들만 잘 정의해 주면 되죠.

따라서 복잡한 조건문 없이도 각각의 상태의 따라 다른 효과를 낼 수 있게 됩니다.

# -*- coding: utf-8 -*-
# State Pattern

import abc

class GamballMachine:
  def __init__(self, numberOfGamBalls):
    self.hasQuaterState = HasQuaterState(self)
    self.noQuaterState = NoQuaterState(self)
    self.soldState = SoldState(self)
    self.soldOutState = SoldOutState(self)

    self.state = self.noQuaterState
    self.count = numberOfGamBalls

  def insertQuater(self):
    self.state.insertQuater()

  def ejectQuater(self):
    self.state.ejectQuater()

  def turnCrank(self):
    self.state.turnCrank()
    self.state.dispense()

  def setState(self, state):
    self.state = state

  def getHasQuaterState(self):
    return self.hasQuaterState

  def getNoQuaterState(self):
    return self.noQuaterState

  def getSoldState(self):
    return self.soldState

  def getSoldOutState(self):
    return self.soldOutState

  def releaseBall(self):
    if self.count != 0:
      self.count = self.count -1
      print 'Release gamball'

  def getCount(self):
    return self.count


class State:
  __metaclass__ = abc.ABCMeta

  @abc.abstractmethod
  def insertQuater(self, gamball_machine):
    pass

  @abc.abstractmethod
  def ejectQuater(self, gamball_machine):
    pass

  @abc.abstractmethod
  def turnCrank(self, gamball_machine):
    pass

  @abc.abstractmethod
  def dispense(self, gamball_machine):
    pass

class HasQuaterState(State):
  def __init__(self, gamball_machine):
    self.gamball_machine = gamball_machine

  def insertQuater(self):
    print 'Already has quater'

  def ejectQuater(self):
    print 'Eject quater'
    self.gamball_machine.setState(self.gamball_machine.getNoQuaterState())

  def turnCrank(self):
    self.gamball_machine.setState(self.gamball_machine.getSoldState())

  def dispense(self):
    pass

class NoQuaterState(State):
  def __init__(self, gamball_machine):
    self.gamball_machine = gamball_machine

  def insertQuater(self):
    print 'Insert quater'
    self.gamball_machine.setState(self.gamball_machine.getHasQuaterState())

  def ejectQuater(self):
    print 'Please input quater first'

  def turnCrank(self):
    print 'Please input quater first'

  def dispense(self):
    pass

class SoldState(State):
  def __init__(self, gamball_machine):
    self.gamball_machine = gamball_machine

  def insertQuater(self):
    pass

  def ejectQuater(self):
    pass

  def turnCrank(self):
    pass

  def dispense(self):
    self.gamball_machine.releaseBall()
    if self.gamball_machine.getCount() > 0:
      self.gamball_machine.setState(self.gamball_machine.getNoQuaterState())
    else:
      self.gamball_machine.setState(self.gamball_machine.getSoldOutState())

class SoldOutState(State):
  def __init__(self, gamball_machine):
    self.gamball_machine = gamball_machine

  def insertQuater(self):
    print 'Gammball was sold out, Eject quater'

  def ejectQuater(self):
    print 'Insert quater fist'

  def turnCrank(self):
    print 'Please insert quater first'

  def dispense(self):
    pass

# Client

gamballMachine = GamballMachine(2)

print '** Insert and Eject **'
gamballMachine.insertQuater()
gamballMachine.ejectQuater()

print '\n ** Insert and Turncrank **'
gamballMachine.insertQuater()
gamballMachine.turnCrank()

print '\n ** Notinsert and Turncrank **'
gamballMachine.turnCrank()

print '\n ** Set soldout state and turncrank **'
gamballMachine.insertQuater()
gamballMachine.turnCrank()
gamballMachine.turnCrank()

print '\n ** Insert quater when sold out **'
gamballMachine.insertQuater()



 

Comments