7.2. State¶
EN: State
PL: Stan
Type: object
7.2.1. Use Cases¶
Changes based on class
Open/Close principle
Using polymorphism
7.2.2. Problem¶
Canvas object can behave differently depending on selected Tool
All behaviors are represented by subclass of the tool interface
from enum import Enum
class ToolType(Enum):
SELECTION = 1
BRUSH = 2
ERASER = 3
class Canvas:
_current_tool: ToolType
def get_current_tool(self) -> ToolType:
return self._current_tool
def set_current_tool(self, tool: ToolType) -> None:
self._current_tool = tool
def mouse_down(self) -> None:
if self._current_tool == ToolType.SELECTION:
print('Selection icon')
elif self._current_tool == ToolType.BRUSH:
print('Brush icon')
elif self._current_tool == ToolType.ERASER:
print('Eraser icon')
def mouse_down(self) -> None:
if self._current_tool == ToolType.SELECTION:
print('Draw dashed rectangle')
elif self._current_tool == ToolType.BRUSH:
print('Draw line')
elif self._current_tool == ToolType.ERASER:
print('Erase something')
7.2.3. Design¶

7.2.4. Implementation¶

from abc import ABCMeta, abstractmethod
class Tool(metaclass=ABCMeta):
@abstractmethod
def mouse_down(self) -> None:
pass
@abstractmethod
def mouse_up(self) -> None:
pass
class SelectionTool(Tool):
def mouse_down(self) -> None:
print('Selection icon')
def mouse_up(self) -> None:
print('Draw dashed rectangle')
class BrushTool(Tool):
def mouse_down(self) -> None:
print('Brush icon')
def mouse_up(self) -> None:
print('Draw line')
class Canvas:
__current_tool: Tool
def mouse_down(self) -> None:
self.__current_tool.mouse_down()
def mouse_up(self) -> None:
self.__current_tool.mouse_up()
def get_current_tool(self):
return self.__current_tool
def set_current_tool(self, newtool: Tool):
self.__current_tool = newtool
if __name__ == '__main__':
canvas = Canvas()
canvas.set_current_tool(SelectionTool())
canvas.mouse_down()
# Selection icon
canvas.mouse_up()
# Draw dashed rectangle
7.2.5. Assignments¶
"""
* Assignment: DesignPatterns Behavioral State
* Complexity: medium
* Lines of code: 34 lines
* Time: 21 min
English:
1. Implement State pattern
2. Then add another language:
a. Chinese hello: 你好
b. Chinese goodbye: 再见
3. Run doctests - all must succeed
Polish:
1. Zaimplementuj wzorzec State
2. Następnie dodaj nowy język:
a. Chinese hello: 你好
b. Chinese goodbye: 再见
3. Uruchom doctesty - wszystkie muszą się powieść
Tests:
>>> polish = Translation(Polish())
>>> english = Translation(English())
>>> chinese = Translation(Chinese())
>>> polish.hello()
'Cześć'
>>> polish.goodbye()
'Do widzenia'
>>> english.hello()
'Hello'
>>> english.goodbye()
'Goodbye'
>>> chinese.hello()
'你好'
>>> chinese.goodbye()
'再见'
"""
from enum import Enum
class Language(Enum):
POLISH = 'pl'
ENGLISH = 'en'
SPANISH = 'es'
class Translation:
__language: Language
def __init__(self, language: Language):
self.__language = language
def hello(self) -> str:
if self.__language is Language.POLISH:
return 'Cześć'
elif self.__language is Language.ENGLISH:
return 'Hello'
elif self.__language is Language.SPANISH:
return 'Buenos Días'
else:
return 'Unknown language'
def goodbye(self) -> str:
if self.__language is Language.POLISH:
return 'Do widzenia'
elif self.__language is Language.ENGLISH:
return 'Goodbye'
elif self.__language is Language.SPANISH:
return 'Adiós'
else:
return 'Unknown language'