多型
getType()
あなたがそれに似たものを使用している限り、ポリモーフィズムは使用していません。
自分のタイプを知る必要があると感じています。しかし、それを知っている間にやりたいことは、実際にクラスにプッシュダウンする必要があります。次に、いつ実行するかを指示します。
手続き型コードは情報を取得してから決定を下します。オブジェクト指向コードは、オブジェクトに何かをするように指示します。
—アレック・シャープ
この原則はテルと呼ばれ、尋ねないでください。それに従うと、タイプなどの詳細を広めたり、それらに作用するロジックを作成したりするのに役立ちます。それを行うと、クラスが裏返しになります。クラスが変更されたときに変更できるように、その動作をクラス内に保持することをお勧めします。
カプセル化
他の形は必要ないだろうと言うことができますが、私はあなたを信じてはいけないし、あなたもそうすべきではありません。
カプセル化に従うことの素晴らしい効果は、新しいタイプを追加するのが簡単なことです。なぜなら、それらの詳細は、それらが現れるロジックif
やswitch
ロジックに広がらないからです。新しい型のコードはすべて1つの場所にある必要があります。
タイプ無知の衝突検出システム
タイプを気にせずに、高性能で任意の2D形状で動作する衝突検出システムをどのように設計するかを説明します。
あなたはそれを描くことになっていたとしましょう。簡単そうです。それはすべて円です。衝突を理解するサークルクラスを作成するのは魅力的です。問題は、これが私たちに1000の円を必要とするときにバラバラになる思考の線を下に送ることです。
サークルについて考えてはいけません。ピクセルについて考える必要があります。
これらの人を描くのに使用するのと同じコードが、彼らが触れたとき、またはユーザーがクリックしたものを検出するために使用できるものであると言ったらどうでしょう。
ここでは、各円を一意の色で描画しました(目が黒の輪郭を見るのに十分であれば、それを無視してください)。これは、この非表示の画像のすべてのピクセルが、描画したものにマップされることを意味します。ハッシュマップはそれをうまく処理します。この方法で実際にポリモーフィズムを行うことができます。
この画像をユーザーに表示する必要はありません。最初のコードを描いたのと同じコードで作成します。色違いです。
ユーザーが円をクリックすると、1つの円だけがその色であるため、どの円かが正確にわかります。
円を別の円の上に描画すると、上書きしようとしているすべてのピクセルをセットにダンプすることですばやく読み取ることができます。衝突したすべての円の設定ポイントが完了したら、衝突を通知するためにそれぞれを1回呼び出すだけで済みます。
新しいタイプ:長方形
これはすべて円を使って行われましたが、私はあなたに尋ねます:それは長方形で異なる動作をしますか?
サークルの知識は検出システムに漏れていません。半径、円周、または中心点は気にしません。ピクセルと色が重要です。
この衝突システムの個々の形状にプッシュダウンする必要がある唯一の部分は、一意の色です。それ以外は、図形は図形の描画について考えることができます。とにかく彼らが得意なものです。
衝突ロジックを記述するとき、サブタイプが何であるかは気にしません。衝突するように指示し、描画するふりをしている図形の下で見つかったものを通知します。タイプを知る必要はありません。また、他のクラスのコードを更新することなく、好きなだけサブタイプを追加できます。
実装の選択肢
本当に、それはユニークな色である必要はありません。それは実際のオブジェクト参照であり、間接的なレベルを保存する可能性があります。しかし、この答えに描かれている場合、それらは見栄えがよくありません。
これは実装の一例にすぎません。確かに他のものがあります。これが意味することは、これらの形状のサブタイプを単一の責任に近づけるほど、システム全体がうまく機能することです。より高速でメモリ集約度の低いソリューションが存在する可能性がありますが、サブタイプの知識を広めることを余儀なくされた場合、パフォーマンスが向上してもそれらを使用することを嫌います。明らかに必要でない限り、私はそれらを使用しません。
ダブルディスパッチ
これまで、二重ディスパッチを完全に無視してきました。できたからです 衝突ロジックが衝突した2つのタイプを気にしない限り、それは必要ありません。必要ない場合は、使用しないでください。あなたがそれを必要とするかもしれないと思うなら、できる限りそれを扱うことを先送りにしてください。この態度はヤグニと呼ばれます。
あなたが決める場合、あなたは本当に、n個の形状のサブタイプは本当に必要なn個ならば、あなたの自己を頼む衝突の種類を必要とする2衝突の種類。これまでのところ、別のシェイプサブタイプを簡単に追加できるように一生懸命取り組んできました。ダブルディスパッチの実装でそれを台無しにしたくはありません。
とにかく何種類の衝突がありますか?少し推測(危険なこと)は、弾性衝突(弾力性)、非弾性(粘着性)、エネルギー(爆発)、および破壊的(損傷)を生み出します。さらに多くの可能性がありますが、これがn 2未満であれば、衝突を過剰に設計しないでください。
これは、私の魚雷がダメージを受け入れる何かに当たったとき、宇宙船に当たったことを知る必要がないことを意味します。「ハハ!あなたは5ポイントのダメージを受けた」と伝えるだけです。
損傷を与えるものは、損傷メッセージを受け入れるものに損傷メッセージを送信します。そのようにして、新しい形状について他の形状に知らせることなく、新しい形状を追加できます。あなたは新しいタイプの衝突の周りに広がるだけです。
宇宙船は「ハハ!あなたは100ポイントのダメージを受けた」とトルプに送り返すことができます。「あなたは今、私の船体にこだわっています」。そして、torpは「さて、私は忘れてしまいました」と返事することができます。
それぞれが何であるかを正確に知ることはありません。彼らは、衝突インターフェイスを介して互いに対話する方法を知っています。
確かに、ダブルディスパッチを使用すると、これよりも詳細に制御できますが、本当に必要ですか?
少なくとも、実際の形状の実装ではなく、形状が受け入れる衝突の種類の抽象化を通じて二重ディスパッチを行うことを検討してください。また、衝突動作は、依存関係として注入し、その依存関係に委任できるものです。
性能
パフォーマンスは常に重要です。しかし、それが常に問題であることを意味するわけではありません。パフォーマンスをテストします。推測するだけではありません。パフォーマンスの名の下で他のすべてを犠牲にしても、通常はパフォーマンスの良いコードにはなりません。