8.2. State

8.2.1. Rationale

  • EN: State

  • PL: Stan

  • Type: object

8.2.2. Use Cases

  • Changes based on class

  • Open/Close principle

  • Using polymorphism

8.2.3. 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')

8.2.4. Design

../_images/designpatterns-state-gof.png

8.2.5. Implementation

../_images/designpatterns-state-usecase.png
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

8.2.6. Assignments

Todo

Create assignments