🎮🔑 Искусство управления доступом в Unity: модификаторы public, private и protected
Public, private и protected — три ключевых слова, которые определяют уровень доступа к полям и методам в C# и Unity. Делимся секретами, как правильно использовать их, чтобы сделать ваш код безопаснее и понятнее.
Одно из первых действий, которое вы, скорее всего, сделаете в скрипте Unity, — это создадите поле. И, скорее всего, сделаете его публичным, как это делают во многих уроках и гайдах.
Например, так:
Ключевое слово public в Unity — это модификатор доступа, который определяет уровень доступности поля (или метода, свойства, класса).
В данном случае сделать что-то публичным, означает разрешить другим классам получать к нему доступ.
Например, на публичный класс могут ссылаться другие классы, публичное поле могут читать и изменять другие скрипты, а публичный метод может быть вызван из любого места в вашей игре.
Даже если вы новичок в Unity, модификаторы доступа, как правило, очень просты в использовании.
Далее мы рассмотрим их особенности и области применения.
Объяснение модификаторов доступа в Unity
Модификаторы доступа в Unity позволяют вам ограничивать область видимости полей, методов, свойств и классов.
Существует четыре основных типа модификаторов доступа:
- Public
- Private
- Protected
- Internal
Вы, вероятно, уже использовали public и private для изменения уровня доступа переменных и функций в своих скриптах.
Protected, в свою очередь, ограничивает доступность типа только классами-наследниками, что может быть для вас новым.
Вы, как правило, будете крайне редко использовать Internal в Unity, так как этот модификатор доступа ограничивает видимость типа в рамках одной сборки, что не так часто используется при разработке игр на этом движке.
Public, вероятно, является модификатором доступа, с которым вы наиболее знакомы.
Public в Unity
Публичные типы не имеют ограничений в области видимости, поэтому могут быть прочитаны и использованы любым другим скриптом.
Чтобы сделать что-то публичным, просто добавьте ключевое слово public при объявлении:
Затем к публичным методам и полям можно будет получить доступ из других классов с помощью ссылки на скрипт, например, вот так:
Как получить доступ к полю из другого скрипта
В Unity сами классы обычно являются публичными, что означает, что, пока у вас есть доступ к пространству имен, в котором они существуют, вы сможете получить к ним доступ из любого места.
Однако класс может быть, по желанию, установлен как Internal, что является типом по умолчанию для классов, структур и перечислений, если вы явно не зададите модификатор доступа.
Например:
Private и protected классы в Unity
Обычно, когда вы создаете класс, вы делаете это непосредственно в глобальном пространстве имен по умолчанию. Хотя разделение частей проекта на различные пространства имён – хорошая и полезная практика, она, однако, не относится к теме данной статьи, а в небольших проектах от этого и вовсе могут отказываться.
В описанном выше случае класс может быть либо Public, либо Internal, что в Unity зачастую означает одно и то же.
Однако, если вы объявляете класс внутри класса, то его можно сделать приватным, что является значением по умолчанию, или защищенным, ограничив его доступ рамками текущего класса и его наследников.
Например:
Это может быть полезно, если вы хотите создать класс как своего рода структуру данных, которую вы собираетесь использовать только в частном порядке в том же скрипте, в котором вы его объявляете.
Поля, помеченные как public, автоматически сериализуются Unity, то есть, если они являются сериализуемым типом (числом, строкой или классом, помеченным атрибутом [Serializable]), они будут отображаться в инспекторе.
Вы можете использовать ключевое слово public, чтобы отобразить значения и ссылки во вкладке Inspector. Однако же, как правило, лучше использовать атрибут [SerializeField], чтобы отобразить значение в инспекторе, оставляя возможность пометить поле как private.
Private в Unity
Приватные поля и методы обеспечивают наименьший уровень доступа и не могут использоваться ничем за пределами тела, в котором они существуют.
Например, приватное поле не может быть прочитано или использовано другим скриптом, даже если у него есть ссылка на класс, в котором это поле существует.
Поля, которые существуют внутри скрипта, обычно являются private по умолчанию:
Readonly в Unity
Хотя модификатор private может быть полезен для ограничения области видимости поля, существуют дополнительные способы ограничения того, как значение может использоваться независимо от того, является ли оно public или private.
Например, модификатор readonly можно использовать для того, чтобы позволить устанавливать значение полю только в месте его объявления и конструкторе класса. Это означает, что переменная только для чтения может быть установлена только один раз при инициализации.
Если конструкторы для вас в новинку, то они, по сути, являются методами, которые вызываются при создании класса и используются для установки каких-либо начальных значений, необходимых объекту для дальнейшей работы.
Пример использования модификатора readonly:
Readonly следует использовать для тех полей, значения которых будут установлены единожды и не будут изменяться в дальнейшем.
Это может быть значение, которое используется во всем скрипте, но которое не должно изменяться в какой-либо момент, даже классом, который его создал.
В качестве альтернативы, если вы хотите создать поле, которое можно изменять только локально, но считывать из других классов, можно предоставить полю возможность глобального доступа на чтение и частной записи.
Один из способов сделать это — использовать автоматически реализуемое свойство, которое объединяет в себе публичный get с частным set:
В большинстве случаев можно ограничиться публичными и приватными полями и методами.
Однако есть еще один модификатор доступа, protected, который обеспечивает больший доступ, чем private, но не делает поле или метод полностью публичным.
Принцип работы protected в Unity
Пометка поля или метода защищенным означает, что только текущий класс и его наследники классы смогут получить доступ к данному типу данных.
Это может быть полезно, когда вы хотите создать базовые характеристики и функциональность, которые будут использовать другие классы, если они являются производными от этого типа.
Protected работает как своего рода промежуточное звено между public и private, позволяя производным классам изменять и использовать защищенные типы, но скрывая их от других, не связанных скриптов.
Например, вы можете создать базовый тип Human, который содержит поле Health и метод Walk.
Если сделать их защищенными, то классы-наследники, такие как Enemy или NPC, смогут вызывать и использовать их, в то время как внешние классы не смогут:
Обычно вам нужно использовать ключевое слово protected только при наследовании, поскольку оно позволяет вам предоставлять классам возможность использовать данные и функциональность их родительских классов.
Виртуальные и переопределенные методы в Unity
При использовании наследования отношения между полями и методами могут быть немного сложнее, чем было описано ранее.
Это происходит главным образом потому, что классы-наследники могут не только использовать, но и изменять методы классов-родителей.
Например, базовый класс и его наследник могут использовать какой-то метод Awake, что может быть проблемой, поскольку один метод того же типа обычно скрывает другой, не давая ему вызываться.
Модификаторы abstract, virtual, override и sealed можно использовать для управления отношениями между иерархическими классами.
Модификатор abstract
abstract — этим модификатором могут быть помечены методы и свойства в абстрактных классах. Абстрактные методы не имеют тела и обязаны быть реализованы в классах-наследниках.
Модификатор virtual
virtual — такие методы и свойства отличаются от абстрактных тем, что могут содержать в себе логику, быть объявлены не в абстрактных классах, а классы-наследники не обязаны их переопределять.
Модификатор override
override — этим ключевым словом обозначаются те методы и свойства, которые переопределяют (то есть дополняют или изменяют) что-либо из базового класса.
Модификатор sealed
sealed — это ключевое слово служит для того, чтобы запрещать классам-наследникам переопределять методы или наследоваться от класса, который помечен таким модификатором.
Эти модификаторы используются в дополнение к модификаторам доступа, поэтому вы обычно будете видеть их вместе с ключевыми словами public, private и protected.
Почему бы просто не сделать все общедоступным?
Когда вы впервые начинаете работать с Unity, особенно если разработка игр для вас в новинку, вы можете обнаружить, что самый простой подход — делать все публичным, чтобы иметь к этому легкий доступ.
В конце концов, если вы единственный человек, который работает над своей игрой, то знаете, как все должно использоваться.
И пока ваш проект небольшой, это может не быть проблемой. Однако по мере роста размера проекта растет и его сложность, увеличивается количество классов, методов, полей и разнообразной логики. И чем больше у вас будет публичных методов и полей в ваших классах, тем быстрее код станет путаться и усложняться.
В результате, как правило, хорошей практикой является делать что-то публичным только тогда, когда это действительно необходимо, ограничивая функциональность скрипта несколькими основными открытыми методами.
Таким образом, даже если вы единственный, кто работает над своей игрой, ваши скрипты будет легче понять и сложнее сломать.
А какой подход к организации доступа к данным используете вы в своих проектах? Делитесь опытом в комментариях!