Adapter Pattern
Part of the Object Oriented Programming section of Coddy's GDScript journey. Lesson 51 of 65.
The Adapter pattern lets an object work with code that expects different methods. The adapter wraps the object and turns each expected call into a call the object understands.
An old class from an earlier project stores health as two numbers:
# old_monster.gd
class_name OldMonster
extends RefCounted
var life := 30
var max_life := 120Your HUD shows anything that has get_label() and get_hp_percent(). A Knight already has both (it returns "Knight" and 80), but OldMonster has neither:
# health_display.gd
class_name HealthDisplay
extends RefCounted
func show_health(target) -> void:
print(target.get_label(), ": ", target.get_hp_percent(), "%")The adapter holds an OldMonster and provides the two methods the display calls:
# monster_adapter.gd
class_name MonsterAdapter
extends RefCounted
var monster: OldMonster
func _init(wrapped: OldMonster) -> void:
monster = wrapped
func get_label() -> String:
return "Monster"
func get_hp_percent() -> int:
return monster.life * 100 / monster.max_life# main.gd
var display := HealthDisplay.new()
display.show_health(Knight.new())
display.show_health(MonsterAdapter.new(OldMonster.new()))Knight: 80%
Monster: 25%Neither OldMonster nor HealthDisplay changed. That matters when you cannot or should not edit a class: it comes from a plugin, another team owns it, or many scripts depend on its names.
The adapter forwards each call and converts the data on the way, here two numbers into one percentage. Multiply before dividing: with integers, 30 / 120 * 100 is 0, while 30 * 100 / 120 is 25.
Challenge
EasyA weather board shows sensors that have get_sensor_name() and get_celsius(), like ModernSensor (modern_sensor.gd). The board is in weather_board.gd. Old thermometers (legacy_thermometer.gd) only offer read_fahrenheit() and get_code(). Write the adapter ThermometerAdapter:
- The constructor stores the wrapped
LegacyThermometer. get_sensor_name()returnsThermometer, a space and the thermometer's code, likeThermometer TH-4.get_celsius()returns the temperature in Celsius:(fahrenheit - 32) * 5 / 9, as afloat.
Do not change the other classes. The supplied code reads how many sensors follow, then one per line: legacy ID FAHRENHEIT or modern NAME CELSIUS. It wraps every legacy thermometer in your adapter and shows all sensors. For legacy 4 98.6 and modern Garden 21.5 the output is:
Thermometer TH-4: 37.0 C
Garden: 21.5 C
Warmest: Thermometer TH-4Your code goes in thermometer_adapter.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 board := WeatherBoard.new()
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
if parts[0] == "legacy":
var old := LegacyThermometer.new(int(parts[1]), float(parts[2]))
board.add_sensor(ThermometerAdapter.new(old))
else:
board.add_sensor(ModernSensor.new(parts[1], float(parts[2])))
board.show_all()
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 Calculator7Signals
What is a Signal?Declaring and EmittingConnecting to SignalsSignals with ArgumentsRecap - Health System10Design Patterns Part 2
Command PatternAdapter PatternDecorator PatternTemplate Method PatternState PatternComposite Pattern2Class 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