Один из шаблонов программирования заключается в представлении определённой концепции в виде данных, например, команд персонажа, которые можно передавать и использовать как данные в коде. В этой мини-игре команды обрабатываются как данные, генерируемые при взаимодействии с интерфейсом и передаваемые персонажу для выполнения.
В данном проекте команда представлена в виде класса abstract, а каждая конкретная команда является подклассом такого класса command, например, forward_command и turnright_command. Использование абстрактного класса для команды означает, что подклассами, не являющимися абстрактными, являются только допустимые команды. Если вы попытаетесь создать экземпляр класса command напрямую, то получите ошибку при попытке скомпилировать код.
Поскольку команды персонажа являются подклассами класса command, их можно применять везде, где ожидается класс command, например, в функции ExecuteCommand() персонажа на предыдущем шаге. Первый параметр в ExecuteCommand() ожидает тип команды, поэтому вы можете свободно использовать экземпляр подкласса command в качестве аргумента.
В каждом подклассе имеется своя реализация метода DebugString(), поэтому при выводе на экран значения команды у него имеется соответствующее текстовое представление. Однако при необходимости в классы можно добавлять новые различия.
Эти классы также имеют уникальный спецификатор, чтобы мы могли сравнивать экземпляры классов. Без этого спецификатора их невозможно сравнить.
Классы также содержат спецификатор computes, что позволяет создавать их экземпляры в области видимости модулей (напрямую в модуле Commands). Это даёт нам возможность создавать единственный уникальный экземпляр, представляющий каждую команду, например, Commands.Forward для команды движения вперёд.
В этом примере используются экземпляры подклассов команд вместо типа enum, что позволяет позднее добавлять новые команды путём создания дополнительных подклассов. Тип enum невозможно изменять или добавлять в него новые значения после того, как опубликована первоначальная версия проекта. Поэтому тип enum следует использовать в том случае, когда вы не предполагаете изменения этих данных после публикации проекта.
Ниже приведён полный код реализации команд.
# This file contains the data representation of all the commands that the NPC can receive
# and utilities for the data to help with debugging and troubleshooting issues.
# Each type of command that the NPC can perform will be an instance of this class.
# The class has the unique specifier to make instances of the class comparable.
# The class has the computes specifier to be able to instantiate it at module-scope.
# The class has the abstract specifier so it cannot be instantiated directly, and
# requires subclasses to implement any non-initialized functions, like DebugString().
command := class<computes><unique><abstract>:
DebugString():string
Следующий шаг
Мы определили команды и теперь вы знаете, как добавлять их в необходимом количестве.
В следующем шаге вы узнаете, как эти команды используются в интерфейсе и как добавить пользовательский интерфейс для управления персонажем.