Рубрики
Без рубрики

Уровень композиции CORT: как написать модульное программное обеспечение

Учебник о том, как реализовать композицию корневой конструкции в Python. Теги с Python, начинающими, учебниками, CodeNewie.

Дизайн-образцы (2 части серии)

Корень композиции – это шаблон дизайна, который помогает вам структурировать программное приложение, реализуя класс, который создает все остальные классы.

В этом примере мы рассмотрим этот шаблон в Python.

Вот график объекта классов, которые мы собираемся реализовать:

Я разработал приложение образца, которое мы собираемся использовать. Он содержит три компонента: ConsoleInputListener, ConsolePrinter и Romaniantrantranslator и класс объекта стоимости: сообщение.

Классы описываются следующим образом:

  • Применение: Корень композиции, клеится все классы вместе.
  • ConsoleInPutListener: Компонент, он читает строку со стандартного ввода.
  • КонсольPrinter: Компонент, он печатает на стандартный выход.
  • Румынский переводчик: Компонент, он переводит английские слова в Румынский.
  • Сообщение: Объект значений, он инкапсулирует строку сообщения.

Программа в интерфейс не реализация

Перед внедрением компонента приложений я собираюсь определить интерфейсы для ConsoleInPutListener, консолипринтера и румынстранлятора. Я собираюсь позвонить им IgrapeListener, принтер и переводчик для простоты.

Причина, по которой я определен интерфейсы *, заключается в том, что я хочу иметь возможность поменять объекты, которые ссылки на класс приложений. В Python переменные не ограничивайте меня ни к одному типу, но если я собираюсь реализовать другие объекты, я хотел бы иметь шаблон, чтобы он поможет мне уменьшить количество ошибок, которые я могу сделать.

Python не имеет поддержки интерфейсов Так что я собираюсь использовать абстрактные классы:

class Printer(metaclass=abc.ABCMeta):
    def print(self, message):
        raise NotImplementedError("print is not implemented")

class InputListener(metaclass=abc.ABCMeta):
    def get_input(self) -> str:
        raise NotImplementedError("get_input is not implemented!")

class Translator(metaclass=abc.ABCMeta):
    def translate(self, message: Message) -> Message:
        raise NotImplementedError("translate must be implemented!")

Каждый класс, который расширяет мои абстрактные классы, должен реализовать его абстрактные методы:

class ConsolePrinter(Printer):
    def __init__(self, prefix: str):
        self._prefix = prefix

    def print(self, message: Message):
        print(self._prefix, message)

class ConsoleInputListener(InputListener):
    def __init__(self, prompt: str):
        self._prompt = prompt

    def get_input(self) -> str:
        return input(self._prompt)

class RomanianTranslator(Translator):
    def translate(self, message: Message) -> Message:
        words_map = {"hello": "salut"}
        message_words = str(message).split(" ")

        for index, word in enumerate(message_words):
            if word.lower() in words_map.keys():
                message_words[index] = words_map[word]

        return Message(" ".join(message_words))

Класс сообщения, ради полноты, только удерживает строку.

class Message:
    def __init__(self, message):
        self._message = message

    def __str__(self):
        return self._message

И, наконец, класс приложений приклеивает все компоненты вместе и создать их внимание:

from input_listener import InputListener, ConsoleInputListener
from message import Message
from printer import Printer, ConsolePrinter
from translator import Translator, RomanianTranslator


class Application:
    def __init__(self):
        self._printer: Printer = ConsolePrinter(">")
        self._translator: Translator = RomanianTranslator()
        self._input_listener: InputListener = ConsoleInputListener("< ")

    def start(self):
        print("starting application.")
        while True:
            user_in = Message(self._input_listener.get_input())
            if str(user_in) == "exit":
                exit(0)

            self._printer.print(self._translator.translate(user_in))

Основной метод просто запустит приложение:

from application import Application


def main():
    app = Application()
    app.start()


if __name__ == '__main__':
    main()

Запуск приложения выводится:

 starting application.
 < hello Dev!
 > salut Dev! 

Теперь, большинство настоящих мировых приложений не так просто, причина, по которой мы проходили весь этот код, чтобы реализовать простой Hello World, следующий: представьте, что у вас есть 10 переводчиков: английский, французский, немецкий … и два принтера: консоль и файл.

Вы можете изменить код приложений для принятия двух параметров: переводчик и принтер используют аргументы для создания правильного переводчика и принтера, не требуя изменения других классов. Вы можете добавить столько принтеров, переводчиков и входных слушателей, сколько пожелаете. Это огромное преимущество.

Если вы должны были встроить весь код в одном классе, добавив больше переводов и дополнительные параметры печати были бы очень болезненными и разочарованными.

Я надеюсь, что моя статья дала вам некоторое понимание композиции корневого шаблона, если я сделал любую ошибку, пожалуйста, не стесняйтесь корректировать меня.:-)

Полный код на моем Github Отказ

Спасибо за чтение!

Дизайн-образцы (2 части серии)

Оригинал: “https://dev.to/nuculabs_dev/composition-root-pattern-how-to-write-modular-software-21p0”