Давайте напишем сочинение! Но это невыполнимая задача. Однако мы можем создать процесс, который, если его запустить бесконечно, создаст бесконечно длинное эссе. . бесконечно длинное Достаточно близко Теперь вы, очевидно, можете создать длинное и повторяющееся эссе с помощью одной строки кода Python: >>> "This is water. " * 20 'This is water. This is water. This is water. This is water. This is water. This is water. This is water. This is water. This is water. This is water. This is water. This is water. This is water. This is water. This is water. This is water. This is water. This is water. This is water. This is water. ' … ухать! Вместо этого в этой статье мы создадим гораздо более интересное эссе, используя шаблон проектирования «Состояние». Зевать Во-первых, мы поймем, что такое конечные автоматы и как они связаны с шаблоном проектирования состояний. Далее мы создадим конечный автомат, который сможет генерировать (достаточно) интересное и бесконечное эссе. Затем мы кратко рассмотрим шаблон проектирования состояний. Наконец, мы переведем этот конечный автомат в объектно-ориентированный код, используя шаблон проектирования состояний. Шаблоны проектирования программного обеспечения — это эффективные способы решения часто возникающих проблем. При правильном применении шаблоны проектирования программного обеспечения, такие как шаблон состояния, могут помочь вам написать более масштабируемое, поддерживаемое и тестируемое программное обеспечение. Государственный аппарат По сути, шаблон проектирования State преобразует конечный автомат в объектно-ориентированный код. Если вы не знакомы с конечными автоматами, это довольно простая концепция. Конечный автомат имеет и . Состояния — это определенные свойства интересующей нас системы, а переходы состояний — это действия, которые изменяют эти свойства и тем самым также вызывают изменение состояния. состояния переходы Поскольку у меня есть опыт работы в робототехнике (помимо прочего) и поскольку в робототехнике широко используются конечные автоматы, я воспользуюсь простым примером робота-пылесоса, чтобы проиллюстрировать, как работают конечные автоматы. Диаграмма конечного автомата рисует интуитивно понятную картину того, как работает робот, даже если вы никогда не сталкивались с конечными автоматами. Давайте разберем эту операцию шаг за шагом. Робот запускается в состоянии (черная точка указывает на стартовое состояние). «Пристыкован» Если робот обнаруживает, что его батарея разряжена, он начинает заряжаться самостоятельно (состояние ), пока его батарея не заполнится полностью. Как только аккумулятор заряжен, он возвращается в состояние . зарядки «Пристыкован» В состоянии , если робот обнаруживает, что пол грязный (и его батарея не разряжена), он начинает мыть пол (состояние ). «Пристыкован» «Уборка» В состоянии , если у робота разряжается батарея, он начинает заряжаться самостоятельно. И если пол чистый, робот возвращается в свою док-станцию (Состояние ). «Уборка» Docked Таким образом, наш робот-пылесос имеет три состояния — , » и » — и имеет переходы, основанные на сенсорном обнаружении пола и его аккумулятора. «Пристыкован» «Уборка «Зарядка Простой конечный автомат для бесконечного эссе Теперь, когда мы понимаем конечные автоматы на базовом уровне, давайте создадим конечный автомат, способный написать бесконечное эссе. Выше представлен конечный автомат, который использует английскую грамматику для создания эссе, состоящего из коротких простых предложений. Обещаю, очень скоро мы доберемся до более интересной версии, но это должно послужить хорошей отправной точкой для понимания. Давайте рассмотрим, как это работает. Начиная с состояния , мы генерируем существительное, выбирая его из некоторого заранее определенного списка существительных. Допустим, наше существительное — «Мир». (предложение на данный момент: «Мир») «Существительное» Затем мы оказываемся в состоянии , генерируя следующий глагол (скажем, «лает»). (предложение на данный момент: «Мир лает») «Глагол» Мы генерируем прилагательное (скажем, «красный») в состоянии . (предложение на данный момент: «Мир лает красным») «Прилагательное» Затем, в состоянии , мы генерируем один из завершающих знаков препинания, например «!». (предложение: «Мир лает красным!») Endmark Наконец, мы вернулись в состояние , чтобы сгенерировать следующее предложение в эссе. существительного Этот конечный автомат может сгенерировать (бессмысленное) эссе, которое выглядит следующим образом. Мир лает красным! Кузен Гарри нарушил правила? Тигры весело мерцают. … Недетерминированный конечный автомат для бесконечного эссе Хотя «недетерминированный» звучит сложно, для наших целей это просто означает добавление некоторой случайности. По сути, мы добавляем своего рода подбрасывание монеты перед переходом в некоторые состояния. Вы поймете, что я имею в виду. Недетерминированный конечный автомат, описанный выше, очень похож на предыдущий. Единственные различия: Отрицания — это такие слова, как «нет» или «не», а союзы — это такие слова, как «и» и «но». В состоянии мы генерируем глагол, а затем подбрасываем монету. Если выпадает решка (вероятность 50%), мы переходим в состояние ; в противном случае мы переходим в состояние . «Глагол» Отрицания Прилагательного Аналогично, в состоянии мы генерируем прилагательное, а затем подбрасываем монету. Если выпадает решка, мы переходим в состояние ; если решка, то переходим в состояние . «Прилагательное» Конъюнкции Endmark Благодаря введению случайности, отрицания и союзов мы теперь можем генерировать более интересные предложения переменной длины. Шаблон проектирования состояний Теперь давайте разберемся, как работает шаблон проектирования состояний. Опять же, помните, что мы пытаемся преобразовать конечный автомат в объектно-ориентированный код. Обратите внимание, что в машине состояний генерации эссе каждое состояние должно сделать две вещи. Выполните какое-либо действие. В данном случае образуется слово (существительное, прилагательное и т. д.). Переход в следующее состояние. От к и так далее. существительного глаголу С точки зрения конкретного государства, ему не нужно знать или делать. Вместо того, чтобы увязнуть в сложности всей системы — всех ее состояний и переходов — мы можем просто сосредоточиться на одном состоянии за раз. На мой взгляд, такого рода и является самым большим преимуществом модели государства. больше ничего изоляция разъединение Ниже у нас есть диаграмма для шаблона проектирования «Состояние». Существует некоторый контекст, в котором действует каждое из состояний, иллюстрируемый классом . Объект контекста имеет атрибут частного состояния, который он использует для вызова текущего состояния для выполнения своего действия. Каждое состояние реализует интерфейс с методами для выполнения его действия или операции и возврата следующего состояния. UML- Context State Если мы сопоставим это с примером создания эссе, диаграмма UML будет выглядеть следующим образом. теперь является абстрактным классом (обозначенным курсивом), а не интерфейсом. Абстрактные классы могут иметь некоторые абстрактные (не реализованные) методы и атрибуты, а другие могут быть определены. Интерфейсы полностью абстрактны: все их методы абстрактны. Я внес это изменение, потому что одинакова во всех состояниях, и избегать дублирования кода полезно. WordState generateWord Давайте разберем каждый из атрибутов и методов, описанных выше. В классе у нас есть: EssayContext : ссылка на текущий объект . state WordState : Список всех слов, сгенерированных на данный момент. essayBody : установщик для изменения атрибута . setState() state : метод добавления следующего слова в текст эссе. addWord() : мы вызываем этот метод для создания нашего эссе; мы останавливаемся, когда длина превышает . generateEssay() essayBody length : возвращает строку сгенерированного эссе. printEssay() В абстрактном классе у нас есть: WordState : Абстрактное свойство (обозначено курсивом) для списка слов, из которого мы выбираем слова для генерации. wordList : метод, который добавляет сгенерированное слово в контекст эссе. generateWord() : абстрактный метод для возврата следующего состояния. nextState() Мы будем использовать в качестве репрезентативного примера для всех других конкретных состояний, унаследованных от . NounState WordState : список существительных, из которого мы выбираем слова для создания. wordList : возвращает следующее состояние. nextState() Теперь у нас есть все необходимое, чтобы реализовать это в коде. Давайте продолжим и сделаем именно это! Код Python Давайте сначала напишем класс в файле с именем . Мы откажемся от верблюжьего случая и перейдем к случаю со змеей, потому что Питон — это... змея (извините). EssayContext essay_context.py from word_state import WordState class EssayContext: def __init__(self, state: WordState): self.state = state self.essay_body: list[str] = [] def set_state(self, state: WordState): self.state = state def add_word(self, word: str): self.essay_body.append(word) def generate_essay(self, length: int): while len(self.essay_body) < length: self.state.generate_word(self) def print_essay(self) -> str: return " ".join(self.essay_body) Затем давайте добавим состояния в файл . word_state.py import abc import numpy as np class WordState(abc.ABC): word_list: list[str] @classmethod def generate_word(cls, context: "EssayContext"): word = np.random.choice(cls.word_list) context.add_word(word) context.set_state(cls.next_state()) @classmethod @abc.abstractmethod def next_state(cls) -> "WordState": pass class NounState(WordState): word_list: list[str] = ["everything", "nothing"] @classmethod def next_state(cls): return VerbState class VerbState(WordState): word_list: list[str] = ["is", "was", "will be"] @classmethod def next_state(cls): heads = np.random.rand() < 0.5 if heads: return NegationState return AdjectiveState class NegationState(WordState): word_list: list[str] = ["not"] @classmethod def next_state(cls): return AdjectiveState class AdjectiveState(WordState): word_list: list[str] = ["fantastic", "terrible"] @classmethod def next_state(cls): heads = np.random.rand() < 0.5 if heads: return ConjunctionState return EndmarkState class ConjunctionState(WordState): word_list: list[str] = ["and", "but"] @classmethod def next_state(cls): return NounState class EndmarkState(WordState): word_list: list[str] = [".", "!"] @classmethod def next_state(cls): return NounState Наконец, давайте добавим код для запуска всего в main.py from essay_context import EssayContext from word_state import NounState if __name__ == '__main__': ctx = EssayContext(NounState) ctx.generate_essay(100) print(ctx.print_essay()) Запуск дает нам следующий результат (каждый раз разный из-за недетерминированности): python main.py 'everything is not terrible and nothing was terrible ! everything will be not fantastic but everything is fantastic . everything will be fantastic . nothing will be fantastic and nothing will be terrible ! everything was not fantastic and everything will be not terrible . everything was terrible . nothing was terrible but nothing will be fantastic ! nothing is not terrible . nothing was not fantastic but everything was not fantastic ! everything will be not fantastic but everything will be terrible ! everything will be not fantastic . everything is fantastic but nothing will be not terrible ! everything will be not fantastic but nothing was not fantastic !' Неплохо для такой простой системы! Мы также можем расширить различные списки слов или добавить больше состояний, чтобы сделать создание эссе более сложным. Мы могли бы даже представить некоторые API-интерфейсы LLM, чтобы вывести наши эссе на новый уровень. Последние мысли Конечные автоматы и шаблон State отлично подходят для моделирования и создания систем с четко определенным понятием «состояние». То есть с каждым состоянием связано определенное поведение и свойства. Робот-пылесос выполняет уборку, док-станцию или зарядку. Ваш телевизор может быть включен или выключен, а кнопки пульта дистанционного управления телевизора будут действовать по-разному в зависимости от состояния телевизора. Он также хорошо подходит для создания или идентификации последовательностей с четко определенным шаблоном. Это относится к нашему примеру создания эссе. Наконец, вы можете спросить: «Какой во всем этом смысл?» Почему мы потратили столько времени на определение различных состояний и классов, чтобы создать это «бесконечное» эссе? Мы могли бы написать 20 (или меньше) строк кода Python, чтобы добиться такого же поведения. Короткий ответ: для лучшей . масштабируемости Представьте себе, если бы вместо трех или пяти штатов у нас было бы 50 или 500 штатов. Это не гипербола; реальные корпоративные системы имеют такой уровень сложности. Внезапно модель «Государство» кажется гораздо более привлекательной из-за ее разъединенности и изоляции. Мы можем просто сосредоточиться на одном состоянии за раз, не держа в голове всю систему. Вносить изменения проще, поскольку одно состояние не влияет на другие. Это также упрощает модульное тестирование, что является важной частью масштабируемой и поддерживаемой системы. В конечном счете, шаблон «Состояние» касается не только управления состояниями; Как и все шаблоны проектирования, это образец построения систем, которые являются настолько же масштабируемыми и удобными в обслуживании, насколько и сложными.