47
  1. C#の抽象ファクトリパターンの良い例ですか?
  2. C#の抽象ファクトリパターンの利点は何ですか?
  3. 抽象ファクトリパターンでC#ジェネリックを使用するにはどうすればよいですか?
  4. 抽象ファクトリパターンでユニットテストする方法は?
4

1 に答える 1

142

まず、Abstract Factory パターンについて読むことをお勧めします。ここで、なぜこのパターンを使用するのかを説明します。

通常、Factory パターンを使用する場合は、Factory にオブジェクトを作成します。特定のクラス (または複数のクラス) の複数の実装がある場合に問題が発生します。これで、これらの複数の実装がグループ化されました。ファクトリがある場合に使用しAbstract Factory patternますが、グループごとにオブジェクトの作成をグループ化したい場合。

さて、上記の説明は完全に明確ではないかもしれないので、例を挙げます。

データ エージェントを含むクラス ライブラリがあるとします。データ エージェントは、さまざまなデータにアクセスして保存する方法を提供します。もちろん、データを保存する方法は複数あります。例: データベース内、XML ファイル内、サービス上、. これらの可能な方法のそれぞれについて、データ エージェントが必要です。ここでの問題は、だれかが XML ファイル用の DataAgentA をデータベース用の DataAgentB と一緒に使用したくないということです (エンティティ A と B があると仮定します)。ユーザーは、ストレージ エンジンを 1 つだけ使用する必要があります。

Abstract Factory パターンを紹介します。

ユーザーがデータ エージェントを直接インスタンス化できないようにしますが、工場からこれらのデータ エージェントを取得する必要があります。(追加の利点は、たとえばデータベース (EF) を使用する場合、データ エージェントが同じコンテキストを使用することを確認するために内部接続を行うことができることです。) これをどのように達成しますか? データ エージェントのコンストラクタを「内部」に設定します。それとは別に、ストレージ エンジンごとに異なるファクトリを作成します。さて、これらのファクトリはすべて同じことを行うので、これらもインターフェース化されています (データ エージェントと同じように、すべて同じことをしなければならないからですよね!?)。

以下にインターフェースを示します。基本的にこれはファクトリ パターンですが、クラスの代わりにインターフェイスについて話しているのは今だけです。

public interface IAgentA 
{
    // Add some methods here!
}

public interface IAgentB
{
    // Add some methods here!
}

public interface IAgentFactory
{
    IAgentA CreateAgentA();
    IAgentB CreateAgentB();
}

2 つのエージェントの場合、XML 用とデータベース ストレージ用の 2 つの実装が可能です (これも一例です。必要な数の実装タイプを使用できます)。これらの実装は次のようになります (以下を参照)。私がコンストラクタを作ったことに注意してくださいinternal!これは、このコード ブロックの後に続く部分に必要です。

public class AgentA_Xml : IAgentA
{
    internal AgentA_Xml()
    { /* Construction here */}

    // IAgentA method implementations
}

public class AgentB_Xml : IAgentB
{
    internal AgentB_Xml()
    { /* Construction here */}

    // IAgentB method implementations
}


public class AgentA_Database : IAgentA
{
    internal AgentA_Database()
    { /* Construction here */}

    // IAgentA method implementations
}

public class AgentB_Database : IAgentB
{
    internal AgentB_Database()
    { /* Construction here */}

    // IAgentB method implementations
}

コンストラクターが内部であるため。これにより、これらのクラスをアセンブリの外でインスタンス化できなくなります。これは、通常、この種のケースで行うことです。次に、工場を作成する必要があります。

public class XMLAgentFactory : IAgentFactory
{
    public IAgentA CreateAgentA()
    {
        return new AgentA_Xml();
    }

    public IAgentB CreateAgentB()
    {
        return new AgentB_Xml();
    }
}


public class DatabaseAgentFactory : IAgentFactory
{
    public IAgentA CreateAgentA()
    {
        return new AgentA_Database();
    }

    public IAgentB CreateAgentB()
    {
        return new AgentB_Database();
    }
}

両方のファクトリがインターフェイスを実装しているため、ユーザーは(この場合、別のストレージ エンジンを使用したい場合) 実装IAgentFactoryを簡単に変更できます。AgentFactoryインターフェイスに対して(明らかに)。

上記の説明で、質問 (1) と (2) の答えが得られることを願っています。

  1. C#のAbstract factoryパターンの良い例?
  2. c# での抽象ファクトリ パターンの利点は何ですか?

あなたの質問に答える(3)。

  1. 抽象ファクトリ パターンで C# ジェネリックを使用するにはどうすればよいですか?

ジェネリックを引き続き使用できます。これは、Abstract Factory パターンを使用しても少しも変わりません。もちろん、一般的なファクトリ メソッド (create メソッド) を作成する必要がありますが、それは問題ではありません。

質問への回答 (4)。

  1. 抽象ファクトリパターンで単体テストを行うにはどうすればよいですか?

他のクラスを単体テストするのと同じです。1つだけ違います。

おそらくクラスのコンストラクター (およびおそらく他の内部メソッド) もテストしたいので、内部コンストラクター (メソッド) を単体テスト プロジェクトから見えるようにする必要があります (そして、 to を変更したくありませんinternal) publicAssemblyInfo.csこれは、プロジェクト (ファクトリとクラスがあるプロジェクト) のファイルに次の行を追加することで簡単に実行できます。

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("My.UnitTest.Namespace")]

MSDNで InternalsVisibleTo 属性に関する詳細情報 (およびコメント) を見つけることができます。

このような質問に答えていただければ幸いです。

于 2012-05-09T09:47:15.183 に答える