情報隠蔽
CoddyのGDScriptジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 28/65。
情報隠蔽は、private変数よりもさらに一歩進んだ考え方です。クラスを使うコードは、そのpublicメソッドが何をするかだけに依存し、クラスがデータをどのように保存しているかには依存しません。そうすれば、そのコードに手を加えずに保存方法を変更できます。
# inventory.gd
class_name Inventory
extends RefCounted
var _counts: Dictionary = {}
func add(item: String, amount: int) -> void:
_counts[item] = _counts.get(item, 0) + amount
func count(item: String) -> int:
return _counts.get(item, 0)
func remove(item: String, amount: int) -> bool:
if count(item) < amount:
return false
_counts[item] -= amount
return truemain.gd は add()、count()、remove() を呼び出し、Dictionary を見ることはありません。後で Inventory が代わりにスロットの Array を保持するようになっても、変更されるのは inventory.gd だけです。
配列または辞書を返すゲッターには注意してください。GDScriptはこれらの値を参照渡しします。呼び出し元が受け取るのはコピーではなく、オブジェクト自身の配列であり、クラスのメソッドを通さずに変更できます。
# quest_log.gd
var _quests: Array[String] = ["Find the key"]
func get_quests() -> Array[String]:
return _quests# main.gd
var journal := QuestLog.new()
var quests := journal.get_quests()
quests.append("Skip the boss")
print(journal.get_quests()) # ["Find the key", "Skip the boss"]代わりにコピーを返します。duplicate()は同じ要素を持つ新しいArrayを作成するため、それへの変更はオブジェクトの外部にとどまります。
func get_quests() -> Array[String]:
return _quests.duplicate()Dictionary、または他のArrayを保持するArrayには、duplicate(true)を使います。内側のArrayとDictionaryもコピーされます。
チャレンジ
簡単playlist.gd に Playlist クラスを書いてください。曲のタイトルをプライベートな Array _songs に保持し、ほかのコードからは次のメソッドだけを使用します。
add(title)はタイトルを追加し、trueを返します。タイトルがすでにプレイリストにある場合は何も変更せず、falseを返します。remove(title)はタイトルを削除してtrueを返します。タイトルがない場合はfalseを返します。count()は曲数を返します。get_titles()は、追加された順にタイトルのコピーを返します。
用意されたコードはコマンド数を読み取り、1行につき1つのコマンド(add Blue Sky または remove Blue Sky)を読み込んで、結果を出力します。最後に get_titles() から Array を取得し、Intruder を追加して逆順にしてから、曲数とタイトルを出力します。これらの変更がプレイリストに影響してはいけません。コマンドが add Blue Sky、add Rain、add Blue Sky の場合、次のように出力されます。
Added: Blue Sky
Added: Rain
Already in the playlist: Blue Sky
Songs: 2
Blue Sky, Rainコードは playlist.gd に記述してください。main.gd には用意された入出力コードがあり、編集できません。
自分で試してみよう
extends Node
func _ready():
# 提供された入出力コード:そのままにしてください
var playlist := Playlist.new()
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ", true, 1)
var title := parts[1]
if parts[0] == "add":
if playlist.add(title):
print("Added: " + title)
else:
print("Already in the playlist: " + title)
elif playlist.remove(title):
print("Removed: " + title)
else:
print("Not found: " + title)
# 取得したリストを変更しようとするコード
var titles := playlist.get_titles()
titles.append("Intruder")
titles.reverse()
print("Songs: %d" % playlist.count())
print(", ".join(playlist.get_titles()))
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: GDScriptオンラインコンパイラ