7

私はしばらくの間、この設計上の問題に苦労してきました。私が何をしようとしているのか、私が見たさまざまなアプローチ、何をしようとしているのか、そしてその理由を説明するために最善を尽くします.

私は同じ種類のオブジェクトを繰り返し扱う科学計算環境で働いています。太陽系を含む銀河を想像してみてください。各太陽系には惑星系が含まれ、各惑星系には月が含まれます。この目的のために、私は状況を「ある」状況と考えています。したがって、構成を使用して、銀河にその太陽系へのアクセスを与え、各太陽系が月にアクセスできる惑星系にアクセスできるようにしました。各カテゴリ:独自のクラスであること。

私が取り組んでいるさまざまな問題には、これらのオブジェクトに関するさまざまなタイプのデータが含まれていることがよくあります。そして、さまざまなタイプのデータが利用可能になると、オブジェクトを使って特定のことができるようになります。したがって、データ型 1 を使用できる場合は、次のクラスを作成します

class GalaxyOne { /* … */ };
class SolarSystemOne { /* … */ };
class PlanetOne{ /* … */ };
class MoonOne{ /* … */ };

そして、データ型 2 を利用できるようになったら、作成します

class GalaxyTwo { /* … */ };
class SolarSystemTwo { /* … */ };
class PlanetTwo{ /* … */ };
class MoonTwo{ /* … */ };

各クラスの複合的な側面は、含まれているクラスへのポインターを含むベクトルなどのコンテナー変数を使用して処理されます。たとえば、各 Galaxy クラス内で見つけることができます。

class GalaxyTwo{ /* … */
protected:
std::vector<SolarSystemTwo*> solarSystems;
/* … */
};

クラスをより高次のクラスに結合したい場合に困難が生じます。

class GalaxyOneTwo: public GalaxyOne, public GalaxyTwo{
/* Additional methods */
};

ただし、GalaxyOneTwo には GalaxyOne と GalaxyTwo のバージョンがあるため、solarSystems ベクトルにあいまいさの問題が生じます。さらに、継承するベクトルには、SolarSystemOneTwo 型ではないオブジェクトへのポインターが含まれています。これは必須です。そこで、すべてのコンテナ変数を配置した場所からすべてのオブジェクトが継承するテンプレート クラスを作成できると考えました。

template<MoonT,PlanetT,SolarSystemT>
    class PrimitiveGalaxy {
    private:
        std::vector<SolarSystemT*> solarSystems
};

class GalaxyOne: public PrimitiveGalaxy <MoonOne,PlanetOne,SolarSystemOne>{
    /* No longer defining any container variables for composition */
};

このアプローチは、これらの基本的な Galaxy タイプ (GalaxyOne および GalaxyTwo) に対して非常にうまく機能します。ただし、結合された銀河タイプを作成しようとすると、あらゆる種類のあいまいさが生じます。

class GalaxyOneTwo: public GalaxyOne, public GalaxyTwo, public     PrimitiveGalaxy<MoonOneTwo,PlanetOneTwo,SolarSystemOneTwo>{
    /* … */
};

GalaxyOneTwo で定義された任意のメソッド内で solarSystems を使用すると、あいまいになります。これは、GalaxyOne と GalaxyTwo から継承された各バージョンで 1 回、GalaxyOneTwo で 3 回の 3 回定義されているためです。

具体的に使用することで、このあいまいさを取り除くことができます

PrimitiveGalaxy::solarSystems

毎回適切なベクトルを参照する必要がありますが、多くの余分な入力と構文が必要になるため、これは望ましくありません。

私は銀河の各タイプと原始銀河との間の友情を使用することを検討しましたが、これには同様のレベルの詳細な記述が必要です.

名前空間がコードの記述を簡素化する可能性があるという予感がありますが、GalaxyOneTwo に対して定義された名前空間内で、solarSystems への参照が PrimitiveGalaxy::solarSystems への参照になるように名前空間を定義する方法がわかりません。

編集:

GalaxyOne と GalaxyTwo の唯一の違いは、solarSystems に含まれるクラスのタイプではないことに注意してください。各クラスは銀河に関連するさまざまなデータを扱うため、多くの違いがあります。したがって、さまざまな状態変数、それらの状態変数のゲッターとセッター、およびデータを計算して出力するメソッドを持つさまざまなクラスを作成します。solarSystems は、問題を引き起こしている機能の例であるため、ここで説明しました。GalaxyOneTwo が作成されると、GalaxyOne と GalaxyTwo で使用されるのと同じデータが使用されるため、それらの変数とメソッドをすべて継承したいと考えています。また、データはさまざまな方法で組み合わせることができるため、GalaxyOneTwo 内でそのための新しいメソッドを作成する必要があります。これらは、私が継承を使用するようになった多くの違いの一部です。そうは言っても、問題を引き起こすのは、構成を可能にするコンテナ変数です。各 solarSystem クラス内には、惑星へのアクセスなどを可能にする同様のベクトルがあります。

編集:

ここで一般的に私の設計哲学に特化した質問については(現在の設計の試みを解決しようとすることに重点を置いたこの質問とは対照的に)、次のリンクを参照してください

4

4 に答える 4

3

class Galaxyone 、 oneなどが必要だと思いますclass SolarSystem。そして、あなたGalaxyOneのものGalaxyTwo SolarSystemOneSolarSystemTwoなどは、これらのクラスからインスタンス化された異なるオブジェクトにすぎません。

class SolarSystem { /* … */ };
class Planet{ /* … */ };
class Moon{ /* … */ };

class Galaxy{ /* … */
 public: // Galaxy(...?...){for (...) {read data??; solarSystem.push_back(createSolarSystem(data)); }
 void AddSolarSystem(SolarSystem* ss){solarSystem.push_back(ss);}
 protected:
   std::vector<SolarSystem*> solarSystems;
   /* … */
};

....

Galaxy GalaxyOne, GalaxyTwo;

この単純なアプローチを使用する方法がない場合...あなたのものを見てみましょう:

class GalaxyOneTwo: public GalaxyOne, 
                    public GalaxyTwo, 
                    public PrimitiveGalaxy<MoonOneTwo,PlanetOneTwo,SolarSystemOneTwo>{
    /* … */
 using PrimitiveGalaxy<MoonOneTwo,PlanetOneTwo,SolarSystemOneTwo>::solarSystems;
 GalaxyOneTwo(){solarSystems.reserve(10);}
};

ここに 3 つのプライベート ベクトルがあります: (使用usingすると、直接アクセス可能になります)

std::vector<SolarSystemOne*   > GalaxyOne::solarSystems;
std::vector<SolarSystemTwo*   > GalaxyTwo::solarSystems;
std::vector<SolarSystemOneTwo*> solarSystems; //GalaxyOneTwo::solarSystems;

これはあなたが必要とするものですか?保護しますか? ここに画像の説明を入力

于 2013-02-25T19:57:37.577 に答える
1

たぶん、データモデルを変更して、コンポーネントベースの何かを実装することができます。各コンポーネントには、さまざまなタイプについて言及したのと同じ状態情報が含まれている可能性があります。そして、仮想関数を継承することができます

class Galaxy
{
  // galaxy information

  // Virtual functions shared among galaxies
  virtual void sharedGalaxyFunction() = 0;

  // Vector containing all solar systems in this galaxy
  std::vector<SolarSystem*> solarSystems_;
};

class SolarSystem
{     
  // solar system info

  // Virtual functions shared among all solar systems
  virtual void sharedSolarSystemFunction() = 0;

  // Vector containing planets
  std::vector<Planets*> planets_;
};

// etc for planets...

次に、さまざまなタイプの太陽系または銀河を継承して、特殊なケースを作成し、仮想関数呼び出しに入力することができます。

class CoolSolarSystem : public SolarSystem
{
  // Special variables

  // Fill in the virtual function
  void sharedSolarSystemFunction();
};

次に、さまざまな基本タイプ内のコンテナーに、特殊なタイプへのポインターを設定できます。仮想関数呼び出しがその情報を十分に処理する場合は、特殊型へのキャストバックを回避できるはずです。

于 2013-02-26T00:29:20.640 に答える
0

だから私があなたの質問を正しく理解していれば:

  1. 銀河にはいくつかの種類があり、それらの間にはまったく共通点がありません。
  2. 同じことが太陽系と惑星系にも当てはまります。
  3. これらの異なる型のコレクションを組み合わせて、その型の基になるメソッドに完全にアクセスしたいと考えています。

これは、boost::anyの場合のように思えます

これで、あなたの Galaxy は次のようになります。

#include <list>
#include <boost/any.hpp>
typedef std::vector<boost::any> collection;
class Galaxy
{
   collection SolarSystems;
   public:
   ...methods...
};
class SolarSystem
{
   collection PlanetarySystems;
   public:
   ...methods...
};
class PlanetarySystem
{
   collection Moons;
   public:
   ...methods...
};

もちろん、これは実際には何もしませんが、それらをグループ化できます。有用なことを行う (メソッドを呼び出す) ためには、型を検出し、その型にキャストしてから、必要なコードを実行する必要があります。

ただし、これによりできることは、さまざまなタイプのオブジェクトをグループ化することです。これは、GalaxyOneTwo で求めていることだと思います。これを行う方法の詳細については、こちらをご覧ください

于 2013-02-26T00:16:28.820 に答える
0

「One」バージョンと「Two」バージョンの間の共通のものを「Common」基本クラスのセットに抽象化する必要があります。

class GalaxyCommon {
    // all the common stuff between GalaxyOne and GalaxyTwo including
    std::vector<SolarSystemCommon *> solarSystems;
    ...
};

class GalaxyOne : public virtual GalaxyCommon {
    // all the stuff that is unique to model One
};

class GalaxyTwo : public virtual GalaxyCommon {
    // all the stuff that is unique to model Two
};

class GalaxyOneTwo : public virtual GalaxyOne, public virtual GalaxyTwo {
    // should be complete
};

--の使用に注意してくださいvirtual。多重継承を適切に機能させるために必要です。

于 2013-02-25T23:29:11.617 に答える