私は高品質のオブジェクト指向コードを作成する方法を学びたいと思っており、SOLIDのような概念を研究しています。現在、小さなゲームエンジン用のエンティティコンポーネントプロセスシステムに取り組んでいます。
現在、私はそれをそのように実装しています:
ScreenStack
sのスタックを含むScreen
がありますScreen
にはEntityManager
とProcessManager
があります。ProcessManager
は、Process
から指定されたすべてのEntityManager
esエンティティを更新します。Process
はすべてのゲームロジックを処理するため、ScreenStack
を使用して画面をプッシュおよびポップできるようにする必要があります。エンティティを作成、削除、変更することもできるため、EntityManager
のScreen
が必要です。基本的にProcess
はゲームのすべてに影響を与えるため、ゲームに関するすべてを知る必要がありますが、それは間違っていると感じています。これをよりよく実装するにはどうすればよいですか?ウィンドウがスローされるプロセスに到達するまで、すべてに明確な依存関係階層があるようです。
また、新しい画面をプッシュしたい場合も密結合のようです。たとえば、MainMenu
画面にメニューの選択をチェックするプロセスがあるとします。 「新規ゲーム」をクリックすると、その時に作成される新しい画面をPushする必要があります。 new
を無作為に投入してはならないようですが、これを行っているようです。
「Tell Do n't Ask」の原則を検討することをお勧めします。 Martin Fowlerが良い紹介をします here
一般的な実装は、通常、クラス間のメッセージング/通知に基づいています。 TDAは、オブジェクト指向言語が設計された「pure OOP」であることに注意してください。最も一般的なOO +関数コードの混合モードとは異なります。
もう1つのアドバイスは、更新からのクエリの分離で作業することです(同じメソッドまたはクラスのコードでもデータを要求して処理することはできません)。偶発的な複雑さの多くを取り除き、SRPを大幅に改善します。
プロセスはゲームに関するすべてを知る必要はありませんが、ゲームが何をするかを知る必要があるかもしれません。これは、クラスとinterfacesの基本的な違いです。 (「D」の部分が塗りつぶされています。)
すべてのオブジェクトが個別で完全に無関係であると想像してください。次に、それらのそれぞれから、インターフェース・インスタンスを提供するサービスへの単一の接続を想像してください。クラス間の各リンクを解除して、一連の動作(インターフェースと呼ばれる)に置き換えることができます。 GetInstance(...)などを呼び出して、既存のインターフェースを取得するか、インターフェースの新しいインスタンスを作成します。使用するオブジェクトは、インスタンスがどこで、いつ作成されたかは関係ありませんが、使用方法は知っています。 (Dependency Injectionを調べたなら、これはなじみのあるものになり始めているかもしれません。)
現実に戻りましょう。インターフェースを使用してオブジェクトの依存関係を分離することは一般的には良い考えですが、すでに持っているすべてのものを作り直す必要はありません。難しいことや適切に機能していないことをリファクタリングし、前進し続けるだけです。
ゲームエンジンをプロセス駆動型にしようとしていると思います。つまりプロセスは、ゲームで何が起こるかを決定し、ゲームの状態を変更します。アイデアは好きですが、ゲームに適用できませんでした(1つしか完成していません)。
問題の核心は、私のゲームが本当にプロセス主導型ではなかったことです。入力はフロントエンド(あなたの場合はScreenまたはScreenStack)から来たので、プロセス駆動型アーキテクチャーを階層化されたものに犠牲にする必要がありました。「フロントエンド」は「バックエンド」を使用します。バックエンドにはほとんどのゲームロジック(プロセスの場合はエンティティ)が含まれていますが、フロントエンドがドライバーです。バックエンドは画面をプッシュできません。バックエンドはフロントエンドについて何も知りません。バックエンドはフロントエンドのスレーブにすぎません。それが私が結局終わったものです。多分あなたのゲームは似ています。