Menu
CoddyTech

Klasy i metody abstrakcyjne

Część sekcji Programowanie obiektowe ścieżki GDScript w Coddy. Lekcja 23 z 65.

Niektóre klasy istnieją wyłącznie po to, by po nich dziedziczyć. Każda figura ma pole powierzchni, ale nie możesz go obliczyć, dopóki nie wiesz, czy figura jest kołem, czy prostokątem. Oznacz taką klasę jako @abstract, w wierszu nad 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 ma sygnaturę i nie ma ciała: nie ma dwukropka ani kodu po niej. Oznacza to, że każde dziecko musi zdefiniować tę metodę. describe() jest zwykłą metodą; dzieci ją dziedziczą i może już wywoływać metody abstrakcyjne.

Nie możesz utworzyć obiektu klasy abstrakcyjnej. Shape.new() zatrzymuje program, zanim się uruchomi, z komunikatem Parse Error: Cannot construct abstract class "Shape".

Klasa pochodna, która implementuje każdą metodę abstrakcyjną, jest zwykłą klasą:

# 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

Jeśli klasa potomna pominie jedną z nich, Godot zgłosi to przed uruchomieniem: Class "Square" must implement "Shape.perimeter()" and other inherited abstract methods or be marked as "@abstract". Dzięki temu każdy obiekt, który możesz utworzyć, ma metody area() i perimeter().

Klasa abstrakcyjna nadal może mieć zmienne i metodę _init(). Klasy potomne wywołują ją za pomocą super(), jak zwykle.

challenge icon

Wyzwanie

Łatwy

Sklep akceptuje dwie metody płatności. Każda płatność ma kwotę i paragon, ale opłata i nazwa zależą od metody.

  • Ustaw PaymentMethod jako klasę abstrakcyjną i zadeklaruj dwie metody abstrakcyjne: fee() -> float oraz method_name() -> String. Napisz receipt(), która zwraca NAME: paid AMOUNT, fee FEE, total TOTAL, podając każdą liczbę z dwoma miejscami po przecinku (suma to kwota powiększona o opłatę).
  • CreditCard: opłata wynosi 3% kwoty (amount * 0.03), a nazwa to Credit card.
  • BankTransfer: opłata wynosi 1.5 albo 0.0, gdy kwota wynosi 100 lub więcej, a nazwa to Bank transfer.

Klasy potomne używają konstruktora PaymentMethod. Dostarczony kod odczytuje liczbę kolejnych płatności, a następnie jeden wiersz dla każdej płatności: card AMOUNT lub transfer AMOUNT. Wypisuje każdy paragon i sumę opłat. Dla card 50 i transfer 120 wypisuje:

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

Umieść swój kod w plikach payment_method.gd, credit_card.gd i bank_transfer.gd. main.gd zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

extends Node

func _ready():
	# Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
	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)
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator GDScript online