Menu
CoddyTech

Паттерн «Адаптер»

Часть раздела Объектно-ориентированное программирование путешествия по GDScript на Coddy. Урок 51 из 65.

Шаблон Adapter позволяет объекту работать с кодом, который ожидает другие методы. Адаптер оборачивает объект и преобразует каждый ожидаемый вызов в вызов, понятный объекту.

Старый класс из более раннего проекта хранит здоровье в виде двух чисел:

# old_monster.gd
class_name OldMonster
extends RefCounted

var life := 30
var max_life := 120

В вашем HUD отображается всё, у чего есть 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 и предоставляет два метода, которые вызывает отображение:

# 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. Это важно, когда вы не можете или не должны редактировать класс: он поставляется с плагином, принадлежит другой команде или от его имён зависят многие скрипты.

Адаптер перенаправляет каждый вызов и преобразует данные по пути — здесь два числа в один процент. Умножай перед делением: при работе с целыми числами 30 / 120 * 100 равно 0, а 30 * 100 / 120 равно 25.

challenge icon

Задание

Легко

Метеостанция отображает датчики, у которых есть get_sensor_name() и get_celsius(), например ModernSensor (modern_sensor.gd). Станция находится в 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.

Не изменяйте остальные классы. Предоставленный код считывает количество следующих датчиков, а затем по одному датчику в каждой строке: 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()
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор GDScript