[БЕЗ_ЗВУКА] [БЕЗ_ЗВУКА] В предыдущем видео мы с вами поговорили, как можно создать простейшего QuestGiver, который будет давать и принимать некоторые квесты. Но это не была полноценная цепочка обязанностей, так как в ней не было ключевого свойства: обработай событие сам или передай следующему. И сейчас мы попробуем на примере ООП изменить тот же самый код с классами, чтобы это свойство выполнялось. Нашего персонажа мы оставим без изменений. Зададим некоторый список констант, которые будут являться, собственно, названиями, идентификаторами наших событий, которые будут происходить: получение квестов, сдача квестов. Для того чтобы наша цепочка обязанностей работала корректно, нам нужно объявить событие, которое происходит и которое мы должны обрабатывать. Опишем его, class Event. [ЗВУК] Объявим у него конструктор, в который мы передадим тип события, у каждого события должен быть свой тип, kind. И сохраним его. [ЗВУК] Теперь давайте объявим, собственно, нашу цепочку, начнем ее писать. Писать цепочку мы начнем с нулевого обработчика, с нулевого звена цепочки. Это звено цепочки не будет делать, в принципе, ничего полезного, Оно будет просто передавать событие на обработку следующему обработчику, если такой обработчик имеется. Определим это: class NullHandler. [ЗВУК] В init мы ему будем передавать следующее звено цепочки, successor, который по умолчанию будет None, и сохраним его в какую-нибудь переменную. [ЗВУК] Объявим метод handle — это и будет наш обработчик. Он может обрабатывать нашего персонажа, character, и реагировать на какое-то событие, event. В NullHandler обработчик не реагирует ни на какие события никак, кроме передачи обработки следующему обработчику. Если следующий обработчик вообще существует, если он is not None, передадим ему это событие, handle (char, event). Теперь настало время описать, собственно, наши квесты в виде цепочки обязанностей. Для этого изменим тот код, который мы написали на предыдущем видео. Для начала наши квесты будут классами, class QuestSpeak, которые будут наследоваться от NullHandler. [ЗВУК] Переопределим метод handle, self, char, event, в соответствии с нашим суперклассом. Если происходит событие, обозначающее квест «поговорить», if event.kind == == == QUEST_SPEAK, то, собственно, мы выполняем то, что должны делать в нашем квесте. Что же делать, если нам приходит какое-то другое событие? Мы его должны передать на обработку следующему звену нашей цепочки. Как мы это сделаем? Else, скажем об этом, «событие дальше», и через метод handle нашего суперкласса передадим, super().handle (char, event). Все остальные квесты будут выполнены в аналогичной манере, поэтому мы не будем тратить время на их написание, а просто скопируем их. [ЗВУК] Теперь поговорим, как же нужно изменить нашего QuestGiver, чтобы он мог работать с цепочкой обязанностей. Во-первых, ему нужно объявить ту самую цепочку, с которой он будет работать, self.handlers, обработчики, = QuestCarry, QuestHunt, QuestSpeak, и последним звеном будет наш NullHandler. Теперь список квестов у нас уже объявлен, и нам нужно реагировать на события. Скажем это, events. Вначале список событий пустой, но мы можем добавить событие нашему обработчику, add_event. Что же происходит, когда событие все-таки случается и когда приходит персонаж брать квесты? Для всех событий, которые могут произойти, [ЗВУК] мы передадим их на исполнение нашей цепочке обязанностей, self.handlers. .handle, что? Собственно, нашего персонажа, character, и наше событие, event. Все. QuestGiver мы описали. Давайте поговорим, как нужно изменить наш тестовый код, чтобы он корректно работал с полноценной цепочкой обязанностей. Для начала объявим список всех возможных событий, которые могут произойти — это, собственно, QUEST_CARRY, QUEST_HUNT и QUEST_SPEAK. После этого объявим нашего QuestGiver. Здесь ничего не отличается. Наш QuestGiver может реагировать на все события из этого списка. Скажем ему об этом, quest_giver.add_event. Выполним данный код. Теперь при тестировании мы так же создадим персонажа, как делали до этого, и попытаемся выполнить квесты. Вначале мы получаем квест «принести доски» «поохотиться на крыс» и «поговорить с фермером», потом мы изменяем полученные квесты на «принести доски» и «поговорить с фермером», то есть удаляем квест «охота на крыс» и видим, что эти два квеста сдаются, а квест «охота на крыс» у нас становится полученным. И при третьем вызове мы сдаем квест «охота на крыс». При этом мы видим, что у нас полноценно работает наша цепочка обязанностей, и когда некоторый обработчик не может обработать событие, он передает обработку следующему обработчику. Таким образом, наша цепочка обязанностей полностью реализована. Она может передавать событие следующему обработчику, если не может справиться сама. Вы в своих, в своем коде можете изменить эти квесты, сделать их более интересными, сделать их какими-то другими, добавить много новых событий. Здесь все квесты одинаковые, но это не обязательно должно быть так. [ЗВУК] [БЕЗ_ЗВУКА]