컴포지트 패턴
Coddy GDScript 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 65개 중 55번째.
Composite 패턴은 단일 객체와 객체 그룹이 동일한 메서드를 가지는 트리를 구성하므로, 코드는 전체 그룹을 하나의 항목처럼 다룰 수 있습니다. 가방에는 항목을 담을 수 있고, 가방 안에 다른 가방을 담을 수도 있으며, 어느 가방이든 같은 방식으로 무게를 물어볼 수 있습니다.
두 종류는 추상 부모를 공유합니다:
# entry.gd
@abstract
class_name Entry
extends RefCounted
var entry_name: String
@abstract func get_weight() -> int
@abstract func display(indent: String) -> void잎은 단일 항목입니다:
# item.gd
class_name Item
extends Entry
var weight: int
func _init(n: String, w: int) -> void:
entry_name = n
weight = w
func get_weight() -> int:
return weight
func display(indent: String) -> void:
print(indent, entry_name, " (", weight, ")")복합 객체는 다른 항목들을 담고 있으며, 각 항목에 물어보는 방식으로 답을 구합니다. 가방 자체의 무게는 1입니다.
# bag.gd
class_name Bag
extends Entry
var contents: Array[Entry] = []
func _init(n: String) -> void:
entry_name = n
func add(entry: Entry) -> void:
contents.append(entry)
func get_weight() -> int:
var total := 1
for entry in contents:
total += entry.get_weight()
return total
func display(indent: String) -> void:
print(indent, entry_name, " [", get_weight(), "]")
for entry in contents:
entry.display(indent + " ")# main.gd
var pouch := Bag.new("Pouch")
pouch.add(Item.new("Gem", 2))
var backpack := Bag.new("Backpack")
backpack.add(Item.new("Sword", 8))
backpack.add(pouch)
backpack.display("")Backpack [12]
Sword (8)
Pouch [3]
Gem (2)Bag.get_weight()는 항목인지 가방인지 확인하지 않습니다. 각 항목에서 같은 메서드를 호출하고, 안에 있는 가방은 자신의 내용물에 물어보며 답합니다. 이 재귀는 트리의 깊이와 관계없이 트리 전체를 순회합니다.
링크는 가방에서 그 안의 항목으로 한 방향으로 이어집니다. 모든 항목이 자신이 들어 있는 가방도 저장한다면, 각 가방과 그 항목은 서로를 가리키게 되어 절대 해제되지 않는 참조 순환이 생깁니다. 항목이 자신이 어디에 있는지 알아야 할 때는 display()가 들여쓰기를 전달하는 것처럼 해당 정보를 인수로 전달하세요.
챌린지
중급Composite 패턴을 사용해 폴더 트리를 만드세요. DiskEntry(disk_entry.gd)는 get_size(), count_files(), list_lines(indent)를 선언합니다. 다음을 작성하세요.
FileEntry: 크기는 자체size이며, 파일 수는1이고,list_lines()는 들여쓰기 다음에NAME (SIZE KB)를 출력합니다.FolderEntry:add(entry)는 자식 항목을 저장합니다. 크기는 자식 항목 크기의 합이고, 파일 수는 자식 항목 파일 수의 합입니다.list_lines()는 들여쓰기 다음에NAME/ (SIZE KB)를 출력한 다음, 들여쓰기에 공백 두 개를 더해 모든 자식 항목을 나열합니다.
제공된 코드는 입력(이어지는 줄의 개수, 다음으로 folder NAME, file NAME SIZE 또는 현재 폴더를 닫는 end)을 바탕으로 트리를 만들고, 트리를 나열한 뒤 합계를 출력합니다. notes.txt(4 KB)와 song.mp3(300 KB)가 있는 Music 폴더를 포함하는 Root 폴더의 출력은 다음과 같습니다.
Root/ (304 KB)
notes.txt (4 KB)
Music/ (300 KB)
song.mp3 (300 KB)
Total: 304 KB, files: 2코드는 file_entry.gd와 folder_entry.gd에 작성하세요. main.gd에는 제공된 입출력 코드가 있으며 수정할 수 없습니다.
직접 해보기
extends Node
func _ready():
# 제공된 입출력 코드: 그대로 유지하세요
var open_folders: Array[FolderEntry] = []
var root: FolderEntry = null
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
match parts[0]:
"folder":
var folder := FolderEntry.new(parts[1])
if open_folders.is_empty():
root = folder
else:
open_folders.back().add(folder)
open_folders.append(folder)
"file":
open_folders.back().add(FileEntry.new(parts[1], int(parts[2])))
"end":
open_folders.pop_back()
root.list_lines("")
print("Total: %d KB, files: %d" % [root.get_size(), root.count_files()])
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 GDScript 컴파일러