Абстрактные классы и методы
Часть раздела Объектно-ориентированное программирование путешествия по GDScript на Coddy. Урок 23 из 65.
Некоторые классы существуют только для наследования. У любой фигуры есть площадь, но вычислить её нельзя, пока неизвестно, является ли фигура кругом или прямоугольником. Пометь такой класс как @abstract, на строке выше class_name:
# shape.gd
@abstract
class_name Shape
extends RefCounted
@abstract func area() -> float
@abstract func perimeter() -> float
func describe() -> String:
return "Area %.1f, perimeter %.1f" % [area(), perimeter()]У @abstract func есть сигнатура, но нет тела: после неё нет двоеточия и кода. Это означает, что каждый дочерний класс должен предоставить этот метод. describe() — обычный метод; дочерние классы наследуют его, и он уже может вызывать абстрактные методы.
Нельзя создать объект абстрактного класса. Shape.new() останавливает программу до её запуска с ошибкой Parse Error: Cannot construct abstract class "Shape".
Дочерний класс, в котором реализован каждый абстрактный метод, является обычным классом:
# rectangle.gd
class_name Rectangle
extends Shape
var width: float
var height: float
func _init(w: float, h: float) -> void:
width = w
height = h
func area() -> float:
return width * height
func perimeter() -> float:
return 2 * (width + height)var rect := Rectangle.new(4.0, 6.0)
print(rect.describe())Area 24.0, perimeter 20.0Если дочерний класс пропустит один из них, Godot сообщит об этом до запуска: Class "Square" must implement "Shape.perimeter()" and other inherited abstract methods or be marked as "@abstract". Поэтому у каждого объекта, который можно создать, есть area() и perimeter().
Абстрактный класс всё ещё может иметь переменные и _init(). Дочерние классы вызывают его с помощью super(), как обычно.
Задание
ЛегкоМагазин принимает два способа оплаты. У каждого платежа есть сумма и чек, но комиссия и название зависят от способа оплаты.
- Сделай
PaymentMethodабстрактным классом и объяви два абстрактных метода:fee() -> floatиmethod_name() -> String. Напишиreceipt(), который возвращаетNAME: paid AMOUNT, fee FEE, total TOTAL, выводя каждое число с двумя знаками после запятой (итог — это сумма платежа плюс комиссия). CreditCard: комиссия составляет 3% от суммы (amount * 0.03), а название —Credit card.BankTransfer: комиссия составляет1.5или0.0, если сумма равна100или больше; название —Bank transfer.
Дочерние классы используют конструктор PaymentMethod. Предоставленный код считывает количество последующих платежей, а затем по одной строке на каждый платёж: card AMOUNT или transfer AMOUNT. Он выводит каждый чек и сумму комиссий. Для card 50 и transfer 120 он выводит:
Credit card: paid 50.00, fee 1.50, total 51.50
Bank transfer: paid 120.00, fee 0.00, total 120.00
Total fees: 1.50Твой код нужно поместить в payment_method.gd, credit_card.gd и bank_transfer.gd. В main.gd находится предоставленный код ввода/вывода, и его нельзя редактировать.
Попробуйте сами
extends Node
func _ready():
# Предоставленный код ввода-вывода: оставьте его без изменений
var count := int(OS.read_string_from_stdin())
var total_fees := 0.0
for i in count:
var p := OS.read_string_from_stdin().split(" ")
var payment: PaymentMethod
if p[0] == "card":
payment = CreditCard.new(float(p[1]))
else:
payment = BankTransfer.new(float(p[1]))
print(payment.receipt())
total_fees += payment.fee()
print("Total fees: %.2f" % total_fees)
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово selfМетодыСвойстваКонструктор (_init)Повторение: простой калькулятор4Полиморфизм
Переопределение методов: повторениеУтиная типизацияАбстрактные классы и методыПроектирование интерфейсовПовторение — калькулятор фигур7Сигналы
Что такое сигнал?Объявление и отправкаПодключение к сигналамСигналы с аргументамиПовторение — система здоровья10Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»2Свойства классов
Переменные экземпляра и классаСтатические функцииСеттеры свойствГеттеры свойствПриватность по соглашениюПовторение — менеджер банковского счёта5Инкапсуляция
Открытые и закрытые членыПроверка данных с помощью сеттеровСокрытие информацииСвойства только для чтенияПовторение — система учета студентов8Продвинутые концепции ООП
Композиция и наследованиеВнутренние классыУзлы как компонентыRefCounted и NodeПеречисления в классах11Проект: Управление библиотекой
Обзор проектаКлассы книг и пользователей3Наследование
Основы наследованияКлючевое слово superПереопределение методовЦепочки наследованияПроверка типов с помощью isПовторение — иерархия сотрудников6Специальные методы
Введение в виртуальные методыМетод _to_stringПользовательские итераторыПовторение: пользовательский список9Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн «Одиночка»Паттерн «Фабрика»Паттерн «Наблюдатель»Паттерн «Стратегия»Потренируйтесь самостоятельно: Онлайн-компилятор GDScript