web-dev-qa-db-ja.com

Pythonで複合パターンを設計する方法は?

コンセプト

ゲームの作成を簡単にするために、個人的なプロジェクトとしてpygameを介してインターフェイスをプログラミングしています。

これまでのところ、次のように動作するアーキテクチャを設計することができました。

  • オブジェクトは、画面上で表示および移動できる表示可能なコンポーネントです
  • オブジェクトは子オブジェクトを持つことができます
  • オブジェクトが自分自身を表示するとき、すべての子に親の表面に自分自身を表示するように要求します。
  • オブジェクトには、コールバックシステム、グラフィックシステム、および物理システムの3つの重要な要素があり、それぞれ動作、表示、移動します。

次に、ゲームの「シーン」を作成するときに、プレーヤー、マウス、地面、モンスターなどの他のオブジェクトを含む「ルート」オブジェクトを作成します。

次に、ルートにそれ自体を表示するように要求するだけで、すべてのオブジェクトが再帰的に表示されます。

最初は複合パターンについて知らずに、OOPの基本のみを設計しました。

私の主な問題は、継承から得られるオブジェクトの代替可能プロパティを、作成した再帰的コンポジションでうまく機能させることでした。

「オブジェクト」と呼ばれる「抽象」クラスがあることを意味します(Pythonには実際にはそのような概念がないため、引用符で囲みます)。表示可能)または "MovingObject"(移動可能)ここでの継承は、オブジェクトの機能を拡張するためのものです。

しかし、私の複合パターンでは、「オブジェクトのグループは単一のオブジェクトと同じであると見なさなければならない」と要求しています。

したがって、オブジェクトからメソッドを再帰的に呼び出すと、一部のメソッドがそのメソッドを持たない可能性があるにもかかわらず、オブジェクトのすべての子からそのメソッドが呼び出されます。

たとえば、次のルート要素を使用してみましょう。

  • ルート(画像)
    • プレーヤー(MovingObject)
    • クラウド(MovingObject)
    • 背景(画像)
    • 太陽(画像)

ここで、ルート要素でメソッドmove()を呼び出して、すべての子を移動したいとします。最初に、ルートはImageインスタンスであるため、move()を認識できないため、移動できません。方法。しかし、たとえそうであっても、子供たちの「背景」と「太陽」はそれを知りませんでした。

そこで、「抽象」オブジェクトクラス内に空のメソッドmove()を置くことにしました。これにより、何も実行しなくても、すべてのオブジェクトがそれを認識できます。

問題は、私のObjectクラスに、再帰的な動作を許可するためだけに、理解も必要もない空のメソッドが含まれていることです。

可能な解決策

次に、すべての「継承と構成」の大騒ぎについて聞いたのですが、私の頭に浮かんだ解決策の1つは、オブジェクトアビリティの継承の使用をやめて、代わりに構成を使用することでした。つまり、たとえば、さまざまなアクションを表す「Body」クラス、「Image」クラス、および「Callback」クラスを作成し、それらをObjectインスタンスに接続して「装備」し、より強力なものにします。 。

しかし、move()を呼び出さなければならないため、これはほとんど変更しないと考え、オブジェクトはBodyプラグインがあるかどうかをチェックして使用します。ただし、move()メソッドがObjectクラス内に存在する必要があります。

ご質問

だから私はあなたに私のパターンについてのアドバイスをするためにみんなに頼っています:

  • 複合パターンがどのように機能するかをよく理解しましたか?
  • 私のアプローチは正しいですか?
  • 「プラグイン」クラスを使用すると役立ちますか?
  • 再帰的な振る舞いは良い考えですか?
  • 私のニーズにより適した他のパターンはありますか?

ヒントをください。

5
Jérôme Martin

クリーンなデザインでは、特定のツリー内のオブジェクトを統一されたインターフェイスで使用する必要があります。あなたの疑問はデザインの匂いを反映しています。

シーンにオブジェクトツリーを配置する目的は、オブジェクトのグループに幾何学的変換を適用できるようにすることです。したがって、移動できないオブジェクトがある場合、それらはツリーに属しません。それは意味がありません。

これが可能な解決策です。バックグラウンドオブジェクトを持つことができるレンダークラス、および可動オブジェクトのルートを持つことができます。すべての可動オブジェクトは移動できます。オブジェクトに適用された変換は、その子に伝達されます。

シーンをレンダリングするには、ルートでrender関数を呼び出して、移動できない背景オブジェクトと実際のシーンの両方をレンダリングする必要があります。

2
Simon Bergot