Composition vs Inheritance
Part of the Object Oriented Programming section of Coddy's GDScript journey. Lesson 40 of 65.
Classes reuse code in two ways. Inheritance (extends) says a class is a kind of another class: a Mage is a Player. Composition says a class has a part: it stores another object in a member variable and hands work over to it:
# 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() returns Car starts, motor running. The car does not know how a motor works: it calls motor.start(). Handing a call to a part like this is called delegation. (The class is named Motor because Engine is already a Godot class.)
Composition pays off when parts change or combine. With inheritance, a walking character and a flying character are two subclasses, and a bat that starts to fly cannot change its class. With composition, the character has a movement part, and switching it is one assignment:
# 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 walks
bat.movement = Fly.new()
print(bat.move()) # Bat fliesHere Walk and Fly extend a small Movement class: the two techniques work together. A GDScript class can extend only one class, so composition is also how one object gets several abilities, by holding several parts.
Use inheritance for a real "is a" relationship that never changes. Use composition when the class "has" something, or when the part must be swapped while the game runs.
Challenge
EasyA knight does not inherit from a weapon: a knight has a weapon, and can switch it. Build both classes.
Weaponstoresweapon_nameanddamage, both set by the constructor:Weapon.new("Sword", 7).Knightstoresknight_name(from the constructor) and a weapon, which isnullat the start.equip(new_weapon)replaces the weapon anddrop()sets it back tonull.attack()returnsAda attacks with Sword for 7 damage, using the knight's name and the weapon's name and damage, orAda has no weaponwhen there is none.
The supplied code reads the knight's name and how many commands follow (equip Sword 7, drop, attack) and runs them. For Ada and attack, equip Sword 7, attack, equip Axe 12, attack, drop, attack it prints:
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 weaponYour code goes in weapon.gd and knight.gd. main.gd holds the supplied input/output code and cannot be edited.
Try it yourself
extends Node
func _ready():
# Supplied input/output code: keep it as it is
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())
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe self KeywordMethodsPropertiesConstructor (_init)Recap - Simple Calculator4Polymorphism
Method Overriding RevisitedDuck TypingAbstract Classes and MethodsInterface DesignRecap - Shape Calculator2Class Properties
Instance vs Static VariablesStatic FunctionsProperty SettersProperty GettersPrivate by ConventionRecap - Bank Account Manager5Encapsulation
Public and Private MembersValidation with SettersInformation HidingRead-Only PropertiesRecap - Student Records System8Advanced OOP Concepts
Composition vs InheritanceInner ClassesNodes as ComponentsRefCounted vs NodeEnums in Classes11Project: Library Management
Project OverviewBook and User Classes3Inheritance
Basic InheritanceThe super KeywordMethod OverridingInheritance ChainsType Checks with isRecap - Employee Hierarchy6Special Methods
Virtual Methods IntroductionThe _to_string MethodCustom IteratorsRecap - Custom List9Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy PatternPractice on your own: Online GDScript compiler