BobDalgleishは、この(アンチ)パターンが「トランプデータ」と呼ばれることをすでに指摘しています。
私の経験では、過剰なトランプデータの最も一般的な原因は、オブジェクトまたはデータ構造に実際にカプセル化されるリンクされた状態変数の束を持っていることです。場合によっては、データを適切に編成するために、オブジェクトの束をネストする必要さえあります。
簡単な例では、同様の性質を持つカスタマイズ可能なプレイヤーキャラクターを持っているゲームを、検討しplayerName
、playerEyeColor
その上と。もちろん、プレーヤーはゲームマップ上の物理的な位置、および現在および最大の健康レベルなどのさまざまな他のプロパティも持っています。
このようなゲームの最初のイテレーションでは、これらのすべてのプロパティをグローバル変数にすることは完全に合理的な選択かもしれません。したがって、グローバル状態には次のような変数が含まれる場合があります。
playerName = "Bob"
playerEyeColor = GREEN
playerXPosition = -8
playerYPosition = 136
playerHealth = 100
playerMaxHealth = 100
しかし、ある時点で、おそらくゲームにマルチプレイヤーモードを追加するために、このデザインを変更する必要があることに気付くかもしれません。最初の試みとして、これらすべての変数をローカルにし、それらを必要とする関数に渡すことができます。ただし、ゲーム内の特定のアクションには、次のような関数呼び出しチェーンが含まれる場合があります。
mainGameLoop()
-> processInputEvent()
-> doPlayerAction()
-> movePlayer()
-> checkCollision()
-> interactWithNPC()
-> interactWithShopkeeper()
...このinteractWithShopkeeper()
機能では、店主がプレーヤーを名前でアドレス指定するため、突然これらすべての機能をplayerName
介してトランプデータとして渡す必要があります。そして、もちろん、店主が青い目をしたプレイヤーがナイーブだと思っており、それらに対してより高い価格を請求する場合、機能のチェーン全体を通過する必要があります。playerEyeColor
この場合の適切な解決策は、もちろん、プレイヤーキャラクターの名前、目の色、位置、健康、およびその他のプロパティをカプセル化するプレイヤーオブジェクトを定義することです。そうすれば、その単一のオブジェクトを、何らかの形でプレーヤーに関係するすべての関数に渡すだけで済みます。
また、上記の関数のいくつかは、そのプレーヤーオブジェクトのメソッドに自然に作成できます。これにより、プレーヤーのプロパティに自動的にアクセスできるようになります。ある意味、これは単なるシンタックスシュガーです。オブジェクトのメソッドを呼び出すと、オブジェクトインスタンスがメソッドに隠されたパラメーターとして効果的に渡されますが、適切に使用するとコードがより明確で自然に見えます。
もちろん、典型的なゲームは、単なるプレーヤーよりもはるかに「グローバル」な状態になります。たとえば、ほぼ確実にゲームが行われる何らかのマップがあり、マップ上を移動するノンプレイヤーキャラクターのリストと、おそらくその上に置かれたアイテムがあります。これらすべてをtrampオブジェクトとして渡すこともできますが、それでもメソッドの引数が乱雑になります。
代わりに、解決策は、永続的または一時的な関係を持つ他のオブジェクトへの参照をオブジェクトに保存させることです。したがって、たとえば、プレイヤオブジェクトは、のような方法がなるように、現在のレベル/マップへの参照を持っているでしょう「ゲームの世界」オブジェクトへの参照を格納する必要があるだろう(そしておそらくどのNPCがあまりにもオブジェクト)player.moveTo(x, y)
には必要ありません。マップをパラメーターとして明示的に指定します。
同様に、プレイヤーキャラクターがペットの犬を追いかけた場合、犬を記述するすべての状態変数を自然に1つのオブジェクトにグループ化し、プレイヤーオブジェクトに犬への参照を与えます(プレイヤーが、たとえば、名前で犬を呼び出す)、またはその逆(犬がプレーヤーの位置を知るため)。そしてもちろん、プレーヤーと犬のオブジェクトを両方ともより一般的な「俳優」オブジェクトのサブクラスにしたいので、同じコードを再利用して、たとえば両方をマップ上で移動することができます。
追伸 例としてゲームを使用しましたが、そのような問題が発生する他の種類のプログラムもあります。しかし、私の経験では、根本的な問題は常に同じである傾向があります。1つまたは複数の相互リンクされたオブジェクトに本当にまとめたい個別の変数(ローカルまたはグローバル)がたくさんあります。関数に侵入する「トランプデータ」が数値シミュレーションの「グローバル」オプション設定またはキャッシュされたデータベースクエリまたは状態ベクトルで構成されているかどうかにかかわらず、解決策は常にデータが属する自然なコンテキストを識別し、それをオブジェクトにすることです(または選択した言語で最も近いものは何でも)。