Дизайн-образцы (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”