Композиция и наследование
Часть раздела Объектно-ориентированное программирование путешествия по GDScript на Coddy. Урок 40 из 65.
Классы повторно используют код двумя способами. Наследование (extends) означает, что класс является разновидностью другого класса: Mage — это Player. Композиция означает, что класс содержит часть: он хранит другой объект в переменной-члене и делегирует ему работу:
# motor.gd
class_name Motor
extends RefCounted
func start() -> String:
return "motor running"
# car.gd
class_name Car
extends RefCounted
var motor := Motor.new()
func start() -> String:
return "Car starts, " + motor.start()Car.new().start() возвращает Car starts, motor running. Машина не знает, как работает мотор: она вызывает motor.start(). Передача вызова такой части называется делегированием. (Класс называется Motor, потому что Engine — уже существующий класс Godot.)
Композиция окупается, когда части изменяются или объединяются. При наследовании персонаж, который ходит, и персонаж, который летает, — это два подкласса, а летучая мышь, начинающая летать, не может изменить свой класс. При композиции у персонажа есть компонент передвижения, и его переключение — это одно присваивание:
# character.gd
class_name Character
extends RefCounted
var char_name: String
var movement: Movement
func _init(new_name: String, new_movement: Movement) -> void:
char_name = new_name
movement = new_movement
func move() -> String:
return char_name + " " + movement.move()
# main.gd
var bat := Character.new("Bat", Walk.new())
print(bat.move()) # Bat ходит
bat.movement = Fly.new()
print(bat.move()) # Bat летаетЗдесь Walk и Fly расширяют небольшой класс Movement: эти две техники работают вместе. Класс GDScript может наследоваться только от одного класса с помощью extend, поэтому композиция — это также способ наделить один объект несколькими возможностями, объединив в нём несколько частей.
Используй наследование для настоящего отношения «является», которое никогда не меняется. Используй композицию, когда у класса что-то «есть» или когда часть нужно заменять во время игры.
Задание
ЛегкоРыцарь не наследуется от оружия: у рыцаря есть оружие, и он может его сменить. Создайте оба класса.
Weaponхранитweapon_nameиdamage, оба задаются конструктором:Weapon.new("Sword", 7).Knightхранитknight_name(из конструктора) и оружие, которое в начале равноnull.equip(new_weapon)заменяет оружие, аdrop()снова присваивает емуnull.attack()возвращаетAda attacks with Sword for 7 damage, используя имя рыцаря, а также имя и урон оружия, либоAda has no weapon, если оружия нет.
Предоставленный код считывает имя рыцаря и количество следующих команд (equip Sword 7, drop, attack), а затем выполняет их. Для Ada и команд attack, equip Sword 7, attack, equip Axe 12, attack, drop, attack он выводит:
Ada has no weapon
Equipped Sword
Ada attacks with Sword for 7 damage
Equipped Axe
Ada attacks with Axe for 12 damage
Dropped the weapon
Ada has no weaponВаш код нужно поместить в weapon.gd и knight.gd. В main.gd находится предоставленный код ввода/вывода, его нельзя редактировать.
Попробуйте сами
extends Node
func _ready():
# Предоставленный код ввода/вывода: оставьте его без изменений
var knight := Knight.new(OS.read_string_from_stdin())
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
if parts[0] == "equip":
knight.equip(Weapon.new(parts[1], int(parts[2])))
print("Equipped ", parts[1])
elif parts[0] == "drop":
knight.drop()
print("Dropped the weapon")
else:
print(knight.attack())
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово selfМетодыСвойстваКонструктор (_init)Повторение: простой калькулятор4Полиморфизм
Переопределение методов: повторениеУтиная типизацияАбстрактные классы и методыПроектирование интерфейсовПовторение — калькулятор фигур7Сигналы
Что такое сигнал?Объявление и отправкаПодключение к сигналамСигналы с аргументамиПовторение — система здоровья10Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»2Свойства классов
Переменные экземпляра и классаСтатические функцииСеттеры свойствГеттеры свойствПриватность по соглашениюПовторение — менеджер банковского счёта5Инкапсуляция
Открытые и закрытые членыПроверка данных с помощью сеттеровСокрытие информацииСвойства только для чтенияПовторение — система учета студентов8Продвинутые концепции ООП
Композиция и наследованиеВнутренние классыУзлы как компонентыRefCounted и NodeПеречисления в классах11Проект: Управление библиотекой
Обзор проектаКлассы книг и пользователей3Наследование
Основы наследованияКлючевое слово superПереопределение методовЦепочки наследованияПроверка типов с помощью isПовторение — иерархия сотрудников6Специальные методы
Введение в виртуальные методыМетод _to_stringПользовательские итераторыПовторение: пользовательский список9Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн «Одиночка»Паттерн «Фабрика»Паттерн «Наблюдатель»Паттерн «Стратегия»Потренируйтесь самостоятельно: Онлайн-компилятор GDScript