Kompozycja a dziedziczenie
Część sekcji Programowanie obiektowe ścieżki GDScript w Coddy. Lekcja 40 z 65.
Klasy ponownie wykorzystują kod na dwa sposoby. Dziedziczenie (extends) oznacza, że klasa jest rodzajem innej klasy: Mage jest Player. Kompozycja oznacza, że klasa ma część: przechowuje inny obiekt w zmiennej składowej i przekazuje mu pracę:
# 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() zwraca Car starts, motor running. Samochód nie wie, jak działa silnik: wywołuje motor.start(). Przekazywanie wywołania do takiej części nazywa się delegowaniem. (Klasa nosi nazwę Motor, ponieważ Engine jest już klasą Godot.)
Kompozycja się opłaca, gdy części się zmieniają lub łączą. W przypadku dziedziczenia postać chodząca i postać latająca to dwie podklasy, a nietoperz, który zaczyna latać, nie może zmienić swojej klasy. W przypadku kompozycji postać ma część odpowiedzialną za ruch, a jej zmiana wymaga tylko jednego przypisania:
# 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 chodzi
bat.movement = Fly.new()
print(bat.move()) # Bat lataTutaj Walk i Fly rozszerzają małą klasę Movement: te dwie techniki działają razem. Klasa GDScript może extend tylko jedną klasę, więc kompozycja to także sposób, w jaki jeden obiekt zyskuje kilka umiejętności, przechowując kilka części.
Używaj dziedziczenia w przypadku rzeczywistej relacji „jest czymś”, która nigdy się nie zmienia. Używaj kompozycji, gdy klasa „ma” coś albo gdy część musi być wymieniana podczas działania gry.
Wyzwanie
ŁatwyRycerz nie dziedziczy po broni: rycerz ma broń i może ją zmieniać. Zbuduj obie klasy.
Weaponprzechowujeweapon_nameidamage, oba ustawiane przez konstruktor:Weapon.new("Sword", 7).Knightprzechowujeknight_name(z konstruktora) oraz broń, która na początku ma wartośćnull.equip(new_weapon)zastępuje broń, adrop()ustawia ją z powrotem nanull.attack()zwracaAda attacks with Sword for 7 damage, używając imienia rycerza oraz nazwy i obrażeń broni, alboAda has no weapon, gdy rycerz nie ma broni.
Dostarczony kod odczytuje imię rycerza i liczbę następujących po nim poleceń (equip Sword 7, drop, attack), a następnie je wykonuje. Dla Ada i poleceń attack, equip Sword 7, attack, equip Axe 12, attack, drop, attack wypisuje:
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 weaponTwój kod umieść w plikach weapon.gd i knight.gd. Plik 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 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())
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe selfMetodyWłaściwościKonstruktor (_init)Powtórka – prosty kalkulator4Polimorfizm
Ponowne omówienie przesłaniania metodDuck typingKlasy i metody abstrakcyjneProjektowanie interfejsówPowtórzenie – kalkulator kształtów7Sygnały
Czym jest sygnał?Deklarowanie i emitowanieŁączenie z sygnałamiSygnały z argumentamiPodsumowanie — system zdrowia10Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytu2Właściwości klas
Zmienne instancji a zmienne statyczneFunkcje statyczneSettery właściwościGettery właściwościPrywatne z konwencjiPodsumowanie — menedżer kont bankowych5Enkapsulacja
Elementy publiczne i prywatneWalidacja za pomocą setterówUkrywanie informacjiWłaściwości tylko do odczytuPodsumowanie – system ewidencji uczniów8Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieKlasy wewnętrzneWęzły jako komponentyRefCounted a NodeTypy wyliczeniowe w klasach11Projekt: Zarządzanie biblioteką
Przegląd projektuKlasy książki i użytkownika3Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe superNadpisywanie metodŁańcuchy dziedziczeniaSprawdzanie typów za pomocą isPodsumowanie – hierarchia pracowników6Metody specjalne
Wprowadzenie do metod wirtualnychMetoda _to_stringWłasne iteratoryPodsumowanie — własna lista9Wzorce projektowe — część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec StrategyPoćwicz samodzielnie: Kompilator GDScript online