1

少し循環依存の問題があります。それは問題なく動作しますが、見苦しいコードになります。これは、スネーク ゲームのコンテキストにあります。

SnakeSegments のベクトルを含むクラス Snake があり、それらの相互作用を管理します (たとえば、個別のエンティティとしてではなく、ユニットとして移動および成長します)。

SnakeSegment が Food オブジェクトと衝突すると、hasEaten メンバーが true に反転します。Snake は、基本的にこのメンバーに対して SnakeSegments を定期的に照会します。いずれかのクエリが正の値を返した場合 (つまり、1 つが食べ物に当たった)、ヘビはユニットとして成長します (つまり、頭を広げて尻尾を縮めます)。これはすべて問題ありませんが、SnakeSegment が食べ物にヒットすると、アラート (シグナル、割り込みなど) を Snake クラスに送信し、Snake クラスに成長を指示する、よりシグナルベースのアプローチを好みます。 . これは、すべてのセグメントをチェックして、Snake の Update 関数に醜いコードが含まれていないことを意味します。代わりに、Snake クラスに OnEat() 関数を用意します。

ただし、これは循環依存につながります。Snake には SnakeSegments のベクトルが含まれており、SnakeSegments には Snake& または Snake* メンバーがあり、食べるときに誰に警告するかを指示します。コードでは、基本的に Snake クラスを事前に宣言する必要があります。

class Snake;
class SnakeSegment
{
...
Snake* alertOnEat;
...
};

私のSnakeクラスは正常に動作します

#include "SnakeSegment.hpp"

class Snake
{
...
std::vector segments;
...
void OnEat();
...
};

これよりも優れたデザインはありますか?ここで発生する問題だけではないことに注意してください。同様の問題が多くの領域で発生します (たとえば、GameWorld には Snake メンバーが含まれており、Snake は GameWorld が死亡したときに警告を発します)。そのため、Snake と SnakeSegment に固有の解決策は私が探しているものではありません。

4

2 に答える 2

4

現在の設計は、ほとんどの状況でまったく問題ありません。はい、それは循環依存関係を作成しますが、それを行う最も簡単で明確な方法でもあります。

ただし、派生クラスに直接依存するのではなく、インターフェイスまたは基本クラス間の依存関係を制限する必要があります。world-snake 依存関係が良い例です。Worldおそらく、すべての可能なゲーム オブジェクト タイプをクラスに認識させたいとは限りません。ただし、できることは、すべてのゲーム オブジェクトを共通GameObjectのクラスから派生させWorld、相互にGameObject依存させることです。

依存関係を回避するためのより複雑な方法もあり、それぞれに長所と短所があり、分離と明確さのレベルがほとんど異なります。それらの中には、関数ポインター、デリゲート、オブザーバー、リスナー、ファンクターなどがあります。

最終的には、柔軟性と関心の明確な分離と引き換えに、アーキテクチャにどの程度の複雑さを導入する準備ができているかということに常に帰着します。

デザインは妥協であることを決して忘れないでください。

于 2010-09-19T18:05:36.327 に答える
3

この問題について調べたいのは、Observer/Observable デザイン パターンです。これにより、監視 (Snake) 監視可能なオブジェクト (SnakeSegment) を作成し、状態が変化したときにすぐに通知を受けることができます。

ウィキペディアには、C++ を含む多くの言語で書かれた良い例があります。

これは、多くの GUI 開発で使用される一般的なパターンであるため、基になるモデル データが変更されたときにビュー レイヤーが変更される可能性があります。

于 2010-09-19T17:33:31.953 に答える