Menu
CoddyTech

데코레이터 패턴

Coddy GDScript 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 65개 중 52번째.

데코레이터 패턴은 같은 메서드를 가진 다른 객체로 객체를 감싸 동작을 추가합니다. 각 래퍼는 내부의 객체를 호출하고 자신의 기능을 더하며, 래퍼는 어떤 순서로든 쌓을 수 있습니다.

# weapon.gd
class_name Weapon
extends RefCounted

func get_damage() -> int:
	return 10

func describe() -> String:
	return "Sword"

데코레이터는 Weapon을 확장하므로 무기가 필요한 곳이라면 어디든 사용할 수 있으며, 감싸고 있는 무기를 보유합니다:

# fire_enchant.gd
class_name FireEnchant
extends Weapon

var inner: Weapon

func _init(wrapped: Weapon) -> void:
	inner = wrapped

func get_damage() -> int:
	return inner.get_damage() + 5

func describe() -> String:
	return inner.describe() + " + Fire"

SharpEnchant도 같은 방식으로 작성되지만, get_damage()는 inner.get_damage() * 2를 반환하고 describe()는 " + Sharp"를 추가합니다.

# main.gd
var weapon: Weapon = Weapon.new()
print(weapon.describe(), ": ", weapon.get_damage())
weapon = FireEnchant.new(weapon)
weapon = SharpEnchant.new(weapon)
print(weapon.describe(), ": ", weapon.get_damage())
Sword: 10
Sword + Fire + Sharp: 30

호출은 안쪽으로 전달됩니다. SharpEnchant는 FireEnchant에 요청하고, FireEnchant는 검에 요청합니다. 검은 10을 반환하고, 화염이 이를 15로 만들며, 날카로움이 두 배로 늘려 30이 됩니다. 순서를 바꾸면 FireEnchant.new(SharpEnchant.new(Weapon.new())) 피해량은 10 * 2 + 5이며, 이는 25입니다.

데코레이터가 없다면 모든 조합마다 자체 하위 클래스를 만들어야 합니다: FireSword, SharpSword, FireSharpSword 등등. 데코레이터를 사용하면 작은 클래스 두 개로 모든 조합을 처리할 수 있고, 새로운 인챈트는 파일 하나만 추가하면 됩니다.

challenge icon

챌린지

중급

커피숍은 데코레이터를 사용해 음료를 만듭니다. Beverage(beverage.gd)는 cost()와 description()을 선언하며, Espresso(espresso.gd, $3)와 Tea(tea.gd, $2)는 이미 작성되어 있습니다. 각 데코레이터는 감싸고 있는 음료를 inner에 저장합니다(생성자는 이미 작성되어 있습니다). 다음 클래스에서 cost()와 description()을 오버라이드하세요.

  • Milk: 비용이 1 더 들며 설명에 + Milk를 추가합니다.
  • Mocha: 비용이 2 더 들며 설명에 + Mocha를 추가합니다.
  • Large: 내부의 모든 항목의 비용을 두 배로 하고 설명 앞에 Large 를 붙입니다.

제공된 코드는 뒤따르는 주문의 개수를 읽은 다음, 한 줄에 하나씩 주문을 읽습니다. 주문은 음료(espresso 또는 tea)와 추가 항목으로 구성되며, 추가 항목은 왼쪽에서 오른쪽 순서로 적용됩니다. espresso milk large와 tea mocha milk의 출력은 다음과 같습니다.

Large Espresso + Milk: $8
Tea + Mocha + Milk: $5

코드는 milk.gd, mocha.gd, large.gd에 작성하세요. main.gd에는 제공된 입력/출력 코드가 들어 있으며 수정할 수 없습니다.

직접 해보기

extends Node

func _ready():
	# 제공된 입력/출력 코드: 그대로 유지하세요
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var words := OS.read_string_from_stdin().split(" ")
		var drink: Beverage = Tea.new()
		if words[0] == "espresso":
			drink = Espresso.new()
		for extra in words.slice(1):
			match extra:
				"milk":
					drink = Milk.new(drink)
				"mocha":
					drink = Mocha.new(drink)
				"large":
					drink = Large.new(drink)
		print("%s: $%d" % [drink.description(), drink.cost()])
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 GDScript 컴파일러