アダプターパターン
CoddyのGDScriptジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 51/65。
Adapterパターンを使うと、異なるメソッドを想定しているコードとオブジェクトを連携させることができます。アダプターはオブジェクトをラップし、想定される各呼び出しを、そのオブジェクトが理解できる呼び出しに変換します。
以前のプロジェクトの古いクラスでは、体力を2つの数値として保存しています:
# old_monster.gd
class_name OldMonster
extends RefCounted
var life := 30
var max_life := 120HUDには、get_label()とget_hp_percent()を持つものなら何でも表示されます。Knightはすでに両方を持っています("Knight"と80を返します)が、OldMonsterはどちらも持っていません。
# health_display.gd
class_name HealthDisplay
extends RefCounted
func show_health(target) -> void:
print(target.get_label(), ": ", target.get_hp_percent(), "%")アダプターはOldMonsterを保持し、ディスプレイが呼び出す2つのメソッドを提供します:
# 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%OldMonsterもHealthDisplayも変更されていません。クラスを編集できない、または編集すべきでない場合に重要です。そのクラスがプラグイン由来である、別のチームが所有している、あるいは多くのスクリプトがその名前に依存している場合などです。
アダプターは各呼び出しを転送し、その過程でデータを変換します。ここでは、2つの数値を1つのパーセンテージに変換しています。割る前に掛け算をします。整数の場合、30 / 120 * 100は0ですが、30 * 100 / 120は25です。
チャレンジ
簡単気象ボードには、ModernSensor(modern_sensor.gd)のように、get_sensor_name()とget_celsius()を持つセンサーが表示されます。ボードはweather_board.gdにあります。古い温度計(legacy_thermometer.gd)が提供するのは、read_fahrenheit()とget_code()だけです。アダプターThermometerAdapterを作成してください。
- コンストラクターは、ラップする
LegacyThermometerを保存します。 get_sensor_name()は、Thermometer、スペース、温度計のコードを返します。たとえば、Thermometer TH-4のようになります。get_celsius()は、摂氏温度を(fahrenheit - 32) * 5 / 9で計算し、floatとして返します。
ほかのクラスは変更しないでください。提供されたコードは、後続するセンサーの数を読み取ってから、各行を1つずつ読み取ります。形式はlegacy ID FAHRENHEITまたはmodern NAME CELSIUSです。すべての古い温度計をアダプターでラップし、すべてのセンサーを表示します。legacy 4 98.6とmodern Garden 21.5の場合、出力は次のとおりです。
Thermometer TH-4: 37.0 C
Garden: 21.5 C
Warmest: Thermometer TH-4コードはthermometer_adapter.gdに記述してください。main.gdには提供された入出力コードがあり、編集できません。
自分で試してみよう
extends Node
func _ready():
# 提供された入出力コード: そのままにしておいてください
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()
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: GDScriptオンラインコンパイラ