私は、プレーヤーが部屋にいるマルチプレーヤーゲームサーバーを設計しています。現在、クライアントやネットワーキングなどの面倒を見るクラスがあります。しかし、このRoomクラスのデザインを見つけるのに苦労しています。たとえば、クライアントの部屋を変更する場合、client.changeRoom(newRoom)
またはnewRoom.addClient(client)
を呼び出す必要がありますか?部屋を出るときはどうですか?クライアントは部屋から自分自身をデタッチすべきですか、それとも部屋がクライアントをデタッチすべきですか?私はここで非常に混乱しています。私が将来後悔するようなデザインになってしまいたくありません。
私へのフラッシュバック LPmud 日では、答えはクライアント(プレーヤー、オブジェクト、...)が1つの部屋から別の部屋に移動され、前の部屋(および部屋内の他のすべて)に通知します事実。
新しい部屋に入ると、クライアントは再び部屋のすべてのものにその入り口を通知します。
すべての部屋(または部屋の中のもの)がこの事実を気にするわけではなく、静かにこのメッセージを無視できます。
LPmudの設計が機能する方法は、部屋が他の部屋にリンクするためのconnivence関数を持つ特別なタイプのオブジェクトであるということです。
roomのある場所から別の場所へのプレイヤーの移動を行うデザインは、かなり多くのルックアップを意味します。
注:ここではサンプル関数としてgetRoom()を使用しています。メソッドは、オブジェクトが含まれているコンテナーを返すgetEnvironment()である可能性があり、すべてのオブジェクトにコンテナーがありました(プレーヤーインベントリのバッグ内のコインcoin-> getEnvironment()
はバッグを取得し、coin-> getEnvironment()-> getEnvironment()
はプレイヤーを取得し、coin-> getEnvironment()-> getEnvironment()-> getEnvironment()
は部屋を取得します...)
プレーヤーは移動するためにme->getRoom()->moveMeTo(newRoom);
を実行する必要があります。これは少し面倒になり、時には、物事がうまくいかなかったときに、別の部屋に移動することを不可能にするような部屋がない場合があります。
「インテリジェンス」のあるもの、actingを行うのはプレイヤーなので、それが部屋で演技を行うものでなければなりません。
_me->getRoom()->notify_all(me,leaving);
me->moveRoom(newRoom);
me->getRoom()->notify_all(me,arriving);
_
私がme->getRoom()->moveMeTo(newRoom);
は上記のように悪いが、上記のme->getRoom()->notify_all(...)
を使用すると言った前に、クライアントがどこにもいない場合、getRoom()はすべてのメッセージを無視するnullオブジェクトなので、何も問題はありません。ただし、moveMeToアプローチでは、nullオブジェクトはすべてのメッセージを無視し、どこにも到達しません。
余談ですが、 LP mudlib をダウンロードして、さまざまなコンポーネントがどのように設計されているかを検討することもできます。何十年にもわたるプログラマーによる数十年にわたる洗練を表す、多くの設計思想が長年にわたってそれに組み込まれてきました。
フック、connivence関数、および構造の位置を確認すると、独自の決定のいくつかを簡単に理解し、再考することができます。
それをトップレベルで見ると、どちらの方向にも進む可能性があり、どちらのソリューションも理論的にはどちらよりも優れています。あなたはすでにそれを知っているか、質問をしません。このジレンマは、オブジェクト指向プログラミングではかなり一般的です。コツは、1レベルの抽象化をより深く見ることです。実装は、ほとんどの場合、他の方法に比べて片方の方法でよりクリーンです。疑問がある場合は、両方の方法で実装してみて、どちらが効果的かを確認してください。
たとえば、client.changeRoom(newRoom)
を選択するとします。それが間違った選択である場合、メソッドは主にnewRoom
オブジェクトの呼び出しで構成されます。
newRoom.populateFurniture()
newRoom.populateNPCs()
newRoom.attachChat()
newRoom.notifyPlayers()
...
これは、多くの場合、あまりにも多くのRoom
メソッドを公開する必要が生じ、カップリングが増加します。 add
sは一般的にコンテナーオブジェクトでうまく機能しますが、あなたのアーキテクチャに精通しておらず、似たようなものを作成したことがないので、それがどのように機能するかわかりません。しかし、私の経験では、両方の方法を試した後の選択は常に盲目的に明白でした。
また、最良の方法が次のように両方の組み合わせである可能性を無視しないでください。
Client::changeRoom(Room newRoom) {
room.removeClient(this)
newRoom.addClient(this)
room = newRoom
}