Factory パターンはグローバル ステートと同じものではないでしょうか?
-
03-07-2019 - |
質問
次のようなクラスがあるとします。
class MonkeyFish { MonkeyFish( GlobalObjectA & a, GlobalObjectB & b, GlobalObjectC & c); private: GlobalObjectA & m_a; GlobalObjectB & m_b; GlobalObjectC & m_c; }
ファクトリを使用しない場合、インスタンスを作成するには次のことを行う必要があります。 MonkeyFish
.
GlobalObjectA a; GlobalObjectB b; GlobalObjectC c; int main() { MonkeyFish * monkey_fish = new MonkeyFish(a, b, c); monkey_fish->go(); }
一方、私が持っている場合は、 MonkeyFishFactory
, 、これを行う必要があるようです:
GlobalObjectA a; GlobalObjectB b; GlobalObjectC c; int main() { MonkeyFishFactory mf_factory(a, b, c); MonkeyFish * monkey_fish = mf_factory.buildMonkeyFish("Bob"); monkey_fish->go(); }
まだグローバルオブジェクトがあります。
たとえMonkeyFishFactory自体が
GlobalObjects
内部的には(つまり、真のグローバルではなくMonkeyFishFactory内にあります)、MonkeyFishFactoryのように見えます 自体 を作成したいときにいつでもアクセスできるように、グローバル オブジェクトである必要があります。MonkeyFish
.
この場合、Factory パターンはグローバル状態と同じものではないでしょうか?
(私は現在、グローバル状態は悪いことであり、それを排除することは良いことであるという前提に基づいて活動しています。)
解決
ここで概念を混乱させていませんか?
Factory パターンは通常、抽象インターフェイスの背後に隠れている具象クラスのインスタンスを返すときに適用されます。この考え方は、呼び出し元にはインターフェイスだけが表示され、オブジェクトの具体的な型を知る必要さえないということです。パラメータに基づいてオブジェクト インスタンスを作成し、作成するオブジェクトの決定に関連するロジックを、オブジェクトを作成するユーザーから切り離すことがすべてです。
あなたが説明しているのは、シングルトン(またはモノステート)とファクトリーの混合です。ファクトリには状態があるため、静的にすることはできません。この場合、Singleton パターンのようなものを適用して、適切なグローバルがその中に隠された単一の Factory インスタンスの作成を制御する必要があります。
class IMonkeyFish {
public:
virtual ~IMonkeyFish() = 0;
virtual void go() = 0;
};
class Factory {
public:
static Factory& instance();
IMonkeyFish* createMonkeyFish();
protected:
Factory(GlobalObjectA& a, GlobalObjectB& b, GlobalObjectC& c);
private:
static Factory *theInstance;
GlobalObjectA& instanceOfA;
GlobalObjectB& instanceOfB;
GlobalObjectC& instanceOfC;
};
Factory& factory = Factory::instance();
IMonkeyFish* fishie = factory.createMonkeyFish();
fishie->go();
の Singleton
パターンはファクトリ インスタンスの作成を制御します。の Factory
パターンは、を実装するオブジェクトの作成に関する詳細を非表示にします。 IMonkeyFish
インターフェース。The Good Thing (TM) は、グローバル状態を隠蔽し、グローバル状態を切り離すことです。 MonkeyFish
インスタンスの作成に関する具体的な詳細。
の使用法または使用の正しさ Singleton
ただし、それはまったく別の問題です。おそらく、それに関するスレッドも多数浮上しているでしょう。
他のヒント
グローバル状態は、それ自体が悪いことではありません。 公開グローバル状態は悪いことです。 Factoryパターンは、グローバル状態をカプセル化するのに役立ちます。これは良いことです。
工場にはグローバルな状態はありません。オブジェクトを作成するだけです。 工場内の状態ではないので。グローバルであっても構いません。
グローバルオブジェクトを残す必要はありません。モンキーフィッシュファクトリーは、必要に応じてGlobalOjectA | B | Cを作成する必要があります。 switchまたはif insideメソッドを使用して、どちらを決定します。
ファクトリー内のオブジェクトの作成に対する制御をカプセル化しました。新しいMonkeyFishが必要なすべての場所で複製するのではなく、インスタンス化の詳細を隠したい場合。テスト、単一責任、デメテルの法則について考えてください。 MonkeyFishを使用するクラスで、MonkeyFishを構築するために必要な作業について知る必要があるのはなぜですか。 MonkeyFishをテストしたい場合はどうしますか?作成の詳細がカプセル化されていない場合はどうしますか?
ファクトリクラスの仕事は、オブジェクトをインスタンス化し、呼び出し元に戻すことです。どのグローバルインスタンス化オブジェクトを使用するかを選択しないでください。したがって、工場の例は正しくありません。次のようになります。
int main()
{
MonkeyFish * monkey_fish = MonkeyFishFactory::buildMonkeyFish("Bob");
monkey_fish->go();
}
通知、グローバルオブジェクトなし、MonkeyFishFactoryはインスタンス化されません。
あなたはファクトリーパターンではなくシングルトンパターンを考えていると思います。シングルトンパターンでは、クラスのインスタンスのみがあります。これは、基本的には、グローバル変数がアタッチされていないことを除き、グローバルオブジェクトと同等になります。
適切な回答を得るには、制約と要件を明記する必要があります。良い答えを得るための最も重要なことは、尋ねるべき質問を知ることです。
提供したコードスニペットでは、グローバルを使用することにしましたが、それはファクトリを使用するかどうかとは関係ありません。それでもこれらのグローバルに依存するファクトリを使用する場合は、残りのコードを積み重ねるだけの別のコードがあります。
達成しようとしていることを明確に述べると、おそらくより良い答えが得られます。