19

事実:

  • マネージャーとスペシャリストという 2 つの主要なクラスがあります。
  • スペシャリストにはいくつかの異なるタイプがあります。
  • スペシャリストは、自分の仕事を成し遂げるために他のスペシャリストの助けを必要とすることがよくあります。
  • マネージャーはすべてのスペシャリストを知っており、最初は各スペシャリストは自分のマネージャーだけを知っています。(これが問題です。)
  • 実行時に、Manager はスペシャリストのリストを作成して保存します。次に、マネージャーはリストを繰り返し処理し、各スペシャリストに初期化を依頼します。初期化中、各スペシャリストはマネージャーに、何らかの説明を満たす他のスペシャリストを提供するように依頼します。これが完了すると、マネージャーはループに入り、スペシャリストは専門的なタスクを順番に実行するよう求められます。

これはまともなパターンのように思えますが、マネージャーにはスペシャリストのリストがあり、スペシャリストにはマネージャーがあるため、循環依存の問題が発生しています。

これは、あるクラスの存在を別のクラスから何らかの形で前方宣言する必要がある場合ですか? (そうなら、どのように?) または、この問題を解決するために何らかの設計パターンを使用する必要がありますか? (もしそうなら?) また... 私はパターン自体はかなり大丈夫だったので、これが悪いことである理由を理解するのを手伝ってくれる人を気にしません.

4

5 に答える 5

26

どちらの場合も、他のクラスを前方宣言します。

Manager.h

class Specialist;

class Manager
{
    std::list<Specialist*> m_specialists;
};

Specialist.h

class Manager;

class Specialist
{
    Manager* m_myManager;
};

クラスのヘッダーファイルを取り込む必要があるのは、そのクラス内でメンバー関数または変数を使用する必要がある場合、またはクラスを値型などとして使用する必要がある場合のみです。クラスの場合、フォワード宣言で十分です。

前方宣言は循環依存関係を解決するためだけのものではないことに注意してください。可能な限り、前方宣言を使用する必要があります。実行可能であれば、追加のヘッダーファイルを含めるよりも常に望ましいです。

于 2010-10-25T21:04:48.383 に答える
12

好みの問題ですが、前方宣言は、循環依存関係がない場合でも、ヘッダー ファイルにインクルードする代わりに適していることがよくあります。(この場所でそれについて議論したくありません。)したがって、問題に前方宣言を適用する方法の例を次に示します。

Manager.h で:

// Forward declaration:
class Specialist;

// Class declaration:
class Manager
{
    // Manager declarations go here.
    // Only pointers or references to
    // the Specialist class are used.
};

Manager.cpp で:

#include "Manager.h"

#include "Specialist.h"

// Manager definitions/implementations
// using the Specialist class go here.
// Full Specialist functionality can be used.

Specialist.h で:

// Forward declaration:
class Manager;

// Class declaration:
class Specialist
{
    // Specialist declarations go here.
    // Only pointers or references to
    // the Manager class are used.
};

Specialist.cpp で:

#include "Specialist.h"

#include "Manager.h"

// Specialist definitions/implementations
// using the Manager class go here.
// Full Manager functionality can be used.
于 2010-10-25T21:14:47.113 に答える
1

あなたが提案するように、1つのオプションは、人々の1人を前方宣言することです:

struct specialist;

struct manager
{
    std::vector<std::shared_ptr<specialist> > subordinates_;
};

struct specialist
{
    std::weak_ptr<manager> boss_;
};

ただし、ツリー構造が多くなる場合 (複数の管理レイヤーがある場合は、person基本クラスも機能します。

struct person
{
    virtual ~person() { }
    std::weak_ptr<person> boss_;
    std::vector<std::shared_ptr<person> > subordinates_;
};

その後、階層内のさまざまなタイプの人々に対して特定のクラスを派生させることができます。これが必要かどうかは、クラスをどのように使用するかによって異なります。

実装が をサポートしていない場合でもstd::shared_ptr、 をサポートしているstd::tr1::shared_ptrか、使用できる可能性がありますboost::shared_ptr

于 2010-10-25T21:03:31.883 に答える
1

これは正常な物です。あなただけが必要です

class Manager;

スペシャリストのヘッダーと

class Specialist; 

マネージャーのヘッダーに

shared_ptrs を使用している場合は、shared_from_this が役立つことがあります。(ループ用ではありませんが、とにかく必要になるように聞こえるためです)

于 2010-10-25T21:04:22.733 に答える
1

他のみんなが中心的な質問に答えている間、私はこれを指摘したいと思いました.

実行時に、Manager はスペシャリストのリストを作成して保存します。次に、マネージャーはリストを繰り返し処理し、各スペシャリストに初期化を依頼します。初期化中、各スペシャリストはマネージャーに、何らかの説明を満たす他のスペシャリストを提供するように依頼します。これが完了すると、マネージャーはループに入り、スペシャリストは専門的なタスクを順番に実行するよう求められます。

これは 2 段階のプロセスである必要があることを指摘しておきます。マネージャーがこれまでに 1 人のスペシャリストしか知らない場合、マネージャーはどのようにしてタスク B に存在するスペシャリストをスペシャリスト 1 に伝えることができますか? したがって、次のものが必要です。

1) マネージャーはスペシャリストのリストを確認し、彼らに身元を明らかにするように依頼します。

2) マネージャーはスペシャリストのリストに目を通し、どの専門分野にアクセスする必要があるかを尋ね、誰がその要件を満たすことができるかを伝えます。

3) マネージャーはスペシャリストのリストを確認し、彼らにアクションを実行するよう指示します。

于 2010-10-25T21:29:36.730 に答える