Menu
CoddyTech

Bileşik Kalıp

Coddy'nin GDScript Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 55 / 65.

Composite tasarım deseni, tek bir nesnenin ve bir nesne grubunun aynı yöntemlere sahip olduğu ağaçlar oluşturur; böylece kod, bütün bir grubu tek bir öğe gibi ele alabilir. Bir çanta öğeler içerir, bir çanta başka çantalar içerebilir ve ağırlığını hepsine aynı şekilde sorabilirsiniz.

Her iki tür de ortak bir soyut üst sınıfı paylaşır:

# entry.gd
@abstract
class_name Entry
extends RefCounted

var entry_name: String

@abstract func get_weight() -> int
@abstract func display(indent: String) -> void

Yaprak tek bir öğedir:

# 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, ")")

Bileşik, başka girdileri içinde tutar ve her birine sorarak yanıt verir. Bir çanta kendi başına 1 ağırlığındadır:

# 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() bir girdinin eşya mı yoksa çanta mı olduğunu asla kontrol etmez: her biri için aynı yöntemi çağırır ve içindeki bir çanta kendi içeriğine sorarak yanıt verir. Bu özyineleme, ne kadar derin olursa olsun tüm ağaç yapısını dolaşır.

Bağlantılar tek yönlüdür; bir torbadan içindekilere gider. Her girdi içinde bulunduğu torbayı da saklasaydı, her torba ve girdileri birbirini işaret ederdi; bu da hiçbir zaman serbest bırakılmayan bir başvuru döngüsü oluştururdu. Bir girdinin nerede olduğunu bilmesi gerektiğinde, display() girintiyi nasıl geçiriyorsa bu bilgiyi de bir bağımsız değişken olarak aşağıya aktarın.

challenge icon

Görev

Orta

Composite deseniyle bir klasör ağacı oluşturun. DiskEntry (disk_entry.gd), get_size(), count_files() ve list_lines(indent) işlevlerini bildirir. Şunları yazın:

  • FileEntry: boyutu kendi size değeridir, 1 dosya sayılır ve list_lines() önce girintiyi, ardından NAME (SIZE KB) ifadesini yazdırır.
  • FolderEntry: add(entry) bir alt öğeyi saklar. Boyutu alt öğelerinin boyutlarının toplamı, dosya sayısı onların sayılarının toplamıdır ve list_lines() önce girintiyi, ardından NAME/ (SIZE KB) ifadesini yazdırır, sonra her alt öğeyi girintiye iki boşluk ekleyerek listeler.

Sağlanan kod, girdiden ağacı oluşturur (kaç satır olduğu, ardından folder NAME, file NAME SIZE veya geçerli klasörü kapatan end), ağacı listeler ve toplamları yazdırır. notes.txt (4 KB) içeren bir Root klasörü ve song.mp3 (300 KB) içeren bir Music klasörü için çıktı şöyledir:

Root/ (304 KB)
  notes.txt (4 KB)
  Music/ (300 KB)
    song.mp3 (300 KB)
Total: 304 KB, files: 2

Kodunuzu file_entry.gd ve folder_entry.gd dosyalarına yazın. main.gd, sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.

Kendin dene

extends Node

func _ready():
	# Sağlanan giriş/çıkış kodu: olduğu gibi bırakın
	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()])
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online GDScript derleyicisi