「空の」アブストラクト/クラスはありますか?


10

もちろんできますが、そのようにデザインするのが合理的かどうか疑問に思っています。

私はブレイクアウトクローンを作成していて、クラスの設計を行っていました。継承する必要はありませんが、C ++で学んだことを適用するために継承を使用したいと思いました。私はクラスの設計について考えていて、次のようなものを思いつきました:

GameObject->基本クラス(xオフセットとyオフセットのようなデータメンバー、およびSDL_Surface *のベクターで構成されます*

MovableObject:> GameObject->抽象クラス+ GameObjectの派生クラス(1つのメソッドvoid move()= 0;)

NonMovableObject:GameObject->空のクラス...コンストラクタやデストラクタ以外のメソッドやデータメンバーはありません(少なくとも今のところは?)

その後、TilesetのようなNonMovableObjectからクラスを派生することを計画していました:NonMovableObject。「空の」抽象クラスまたは単に空のクラスが頻繁に使用されるかどうか疑問に思っていました...私はこれを行っている方法で、分類のためにクラスNonMovableObjectを作成していることに気付きました。

私はブレイクアウトクローンを作成するためだけに考えすぎていることを知っていますが、私の焦点はゲームではなく、継承の使用とある種のゲームフレームワークの設計にあります。

回答:


2

C ++では多重継承があるので、これらの空のクラスを持つことは文字通り何のメリットもありません。BallがGameObjectとMovableObjectを後で継承するようにする場合(たとえば、GameObjectの配列を保持し、n秒ごとにTickメソッドを呼び出してすべてを移動させる場合)、それは簡単に実行できます。

しかし、そのような状況では、代わりに、「継承よりも構成(カプセル化)を好む」という公理を覚えて、状態パターンを確認することを個人的に提案します。各オブジェクトに後でその移動状態を持たせたい場合は、それをGameObjectに渡します。例:ボールの場合はDiagonalBouncingMovementState、パドルの場合はHoriazontalControlledMovementState、レンガの場合はNoMovementState。

1)これにより、ユニットテストを簡単に記述できるようになります(繰り返しますが、これもお勧めします)。GameObjectと各状態を個別にテストできるためです。

2)レンガから落ちるトークンがあるが、そのうちの1つを斜めに移動するように変更したいとします。クラス継承の複雑な階層の周りに移動するのではなく、渡されるハードコードされた移動状態を変更できます。 。

3)最も重要なこと:それらのトークンに基づいてボールやパドルがどのように動くかをゲーム内で変更たい場合、その移動状態を変更し続けるだけです(DiagonalMovementStateはDiagonalWithGravityMovementStateになります)。

しかし、これは継承が常に悪いことを示唆するものではなく、継承よりもカプセル化を好む理由を示すためだけのものです。それでも、GameObjectから各タイプのオブジェクトを派生させ、それらのクラスに初期の移動状態を理解させることができます。C ++にはインターフェースがないため、ほぼ確実に、MovementStateクラスの抽象から各移動状態を導出する必要があります。

$ 0.02


8

Javaでは、「空の」インターフェースがマーカー(Serializableなど)として使用されます。これは、実行時にオブジェクトがそのインターフェースを「実装」しているかどうかをチェックできるためです。しかし、C ++では、それは私にはかなり無意味なようです。

IMO、言語機能は、ツールではなく、特定の目標を達成するのに役立つものであり、義務ではありません。あなただけのためにできる機能を使用して、あなたが意味するものではありませんする必要があります。意味のない継承は、プログラムを改善するものではありません。


3

あなたはそれを考え過ぎではありません。あなたは考えていて、それは良いことです。

すでに述べたように、言語機能があるからといって使用しないでください。学習言語機能のトレードオフは、優れた設計の鍵です。

分類に基本クラスを使用しないでください。これはタイプのチェックに関係する可能性があります。それは悪い考えです。

オブジェクトのコントラクトを定義する純粋な抽象化を記述することを検討してください。オブジェクトのコントラクトは、外向きのインターフェイスです。その公開インターフェース。それは何ですか。

注:これは、これは理解することが重要であるではない、それは持っているもののデータxyそれが何をしますかmove()

あなたのデザインには、クラスがありGameObjectます。機能ではなく、データを信頼しています。あなたの場合とで、一般的な共有データのように見えるものを共有するために継承を使用すること効率的で正しいと感じています。xy

これは継承の正しい使い方ではありません。継承は、可能性のある最も緊密な結合形式であり、常に疎結合に努める必要があることを常に覚えておいてください。

その性質上NonMovableObject、移動しません。そのx、そしてy最も確実に宣言されるべきconstです。その性質MoveableObject上、移動する必要があります。xand yとして宣言することはできませんconst。したがって、これは同じデータではなく、共有することはできません。

オブジェクトの機能または契約を検討してください。彼ら何をすべきか?その権利を取得し、データが来るでしょう。一度に1つのオブジェクトで作業します。順番にそれぞれについて心配。あなたの良いデザインは再利用可能です。

おそらくないのでしょうNonMovableObject。メソッドGameObjectBaseを定義する純粋な抽象化はmove()どうですか?システムは実装するGameObjectsをインスタンス化move()し、システムは移動する必要があるもののみを移動します。

これは始まりにすぎない; 味。ウサギの穴はずっと深くなります。スプーンはありません。


どちらMovableObjectNonMovableObject継承できないことは事実ですが、どちらにも場所があります。そのため、それらは両方とも、たとえば、オブジェクトが動くかどうかに関係なく、オブジェクトにモンスターの狙いを向けたいコードによって消費される必要があります。
スーパーキャット2014年

2

言及されたammoQのようなC#のアプリケーションがありますが、C ++での唯一のアプリケーションは、NonMovableObjectポインターのリストが必要な場合のみです。

しかし、私はあなたがNonMoveableObjectポインタを介してオブジェクトを破棄することを想像します。その場合、仮想デストラクタが必要になり、それは空のクラスではなくなります。:)


私もそのケースについて考えましたが、動作を公開しないオブジェクトのそのようなリストで何ができますか?ほとんどの場合、実際の型を見つけてキャストを使用して、使用可能なメソッドとフィールドにアクセスします。コードのにおいは間違いありません。
user281377

はい、それは良い点です。
tenpn

1

これが発生する可能性のある状況の1つは、強力に結合されたコレクションに異種の型を含める必要がある場合です。これは素晴らしいアイデアだと言っているのではありません。抽象化が弱いか、デザインが悪いことを示している可能性がありますが、それは起こります。あなたが言うようにそれはものを分類する方法であり、それは有用で完全に有効である場合があります。

たとえば、猫と犬を保持するコレクションが必要です。あなたのデザインでは、共通点が多いと判断したので、Mamalの基本クラスを用意し、このタイプをコレクション(リストなど)で使用します。すべて良い。次に、カエルをコレクションに追加したいが、それらは哺乳類ではないため、これを行う1つの方法は、カエルと哺乳類の動物のサブクラスを作成することですが、カエルと哺乳類の多くは考えられない一般的なので、動物は空のままです。次に、Mamalの代わりにAnimalを使用してコレクションを入力します。すべて順調です。

実生活では、遅かれ早かれ空の基本クラスを作成したとしても、いくつかの機能がそこに含まれることに気づきますが、それらが存在する場合は確かにあります。


ただし、1つの質問は、型に共通点がない場合、なぜ同じコレクションに保持されているのですか?コレクション内のすべてのアイテムに対して実行できる操作はありません。これは、そのようなコレクションを持つ目的に反するものです。...それは再び便利になるかもしれない、その時点で、しかし今、彼らは共通で何かを持っている-例えばビジターデザインパターンを実装する-今、あなたはロジックを簡素化するために、両方に追加したいかもしれないいくつかの人工的な操作があるかもしれません
ジュール・
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.