2011-10-30 12 views
2

どのようにFactoryを使用する方が良い(正しい)のですか?工場パターンの使用

IPacket info = PacketFactory.CreatePacketObject(PacketType.Info, currentUser, DateTime.Now, " disconnected"); 

または私はPacketFactoryで第二の方法を投げると、このいずれかを使用する必要がありますか?

IPacket info = PacketFactory.CreatePacketObject(PacketType.Info); 
      info.CreationTime = DateTime.Now; 
      info.Creator = currentUser; 
      info.Data = " disconnected"; 

または多分?

PacketFactoryコード:

public static class PacketFactory 
    { 
     public static IPacket CreatePacketObject(PacketType type) 
     { 
      IPacket packetToCreate = null; 
      switch (type) 
      { 
       case PacketType.Info: 
        packetToCreate = new Info(); 
        break; 
       case PacketType.Log: 
        packetToCreate = new Log(); 
        break; 
       case PacketType.Message: 
        packetToCreate = new Message(); 
        break; 
      } 
      return packetToCreate; 
     } 

     public static IPacket CreatePacketObject(PacketType type, Client creator, DateTime creationTime, string data) 
     { 
      IPacket packetToCreate = null; 
      switch (type) 
      { 
       case PacketType.Info: 
        packetToCreate = new Info(creator, creationTime, data); 
        break; 
       case PacketType.Log: 
        packetToCreate = new Log(creator, creationTime, data); 
        break; 
       case PacketType.Message: 
        packetToCreate = new Message(creator, creationTime, data); 
        break; 
      } 
      return packetToCreate; 
     } 

    } 
+0

言い難い文脈がありません。あなたの簡単な例では、私は全く工場を使用しません。 – CodesInChaos

+0

ファクトリの結果を(例のためではなく)プロダクションコードにキャストしている場合は、それがコードの匂いです。インタフェースを介してのみ、工場の結果を参照してください。 – TrueWill

+0

@TrueWill ok、この場合はどうなっていますか? – Saint

答えて

7

パターンを適用する前に、パターンを適用する前に、パターンを適用する前に、静的な「ファクトリ」を導入することで何かを得ることは実際にはわかりません。 PacketFactoryのクライアントの視点から見てください:それはクライアントと様々な具体的な実装者の間のカップリングを減らしたことを紹介してIPacket?私は、PacketType.Info,PacketType.MessageまたはPacketType.Logのいずれかの列挙値を指定することによって、クライアントが既にIPacketの種類を知っていなければならないことから、議論するつもりはありません。 InfoMessage、およびLogクラスについて、クライアントとどのように違うのですか? "Factory"は静的クラスなので、クライアントはIPacketの型に結合されているのと同じように、適切なIPacket実装者のコンストラクタを呼び出したのと同じように返されます。どちらの場合も、異なるタイプのIPacketで作業してください。

実際に何らかの種類のファクトリを使用する必要がある場合は、抽象ファクトリパターンを使用して、ファクトリのクライアントがファクトリインタフェースのみに依存するようにして、さまざまな種類のIPacket変更する必要はありません。たとえば、次のように限り、クラスの不変条件に依存し、工場出荷時は1が作成者を指定せずにIPacketを構築できるようにする必要があるかどうかなどのデータと作成時間やない

public interface IPacketFactory 
{ 
    IPacket CreatePacket(); 
    IPacket CreatePacket(Client creator, DateTime creationTime, string data); 
} 

public class MessageFactory : IPacketFactory 
{ 
    public CreatePacket() 
    { 
     return new Message(); 
    } 

    public CreatePacket(Client creator, DateTime creationTime, string data) 
    { 
     return new Message(creator, creationTime, data); 
    } 
} 

//You'd implement factories for each IPacket type... 

public class Client 
{ 
    private IPacketFactory _factory; 

    public Client(IPacketFactory factory) 
    { 
     _factory = factory; 
    } 

    public SomeMethodThatNeedsToCreateIPacketInstance() 
    { 
     IPacket packet = _factory.CreatePacket(); 

    //work with packet without caring what type it is 
    } 

} 


//a higher level class or IOC container would construct the client with the appropriate factory 

Client client = new Client(new MessageFactory()); 

// the Client class can work with different IPacket instances without it having to change (it's decoupled) 

Client client2 = new Client(new LogFactory()); 

。フィールドが指定されていないときにクラス不変条件を満たすことができれば、それは問題ありません。クラスの仕事の一部は、そのクラスのユーザーがそうであることに依存するため、無効な状態で構築できないようにすることです。

Abstract Factoryパターンは、すべての実装のための統一されたインタフェースが必要であるので、それは理にかなっている場合は、すべての工場が持っている:IPacket実装の一つは、追加のパラメータを必要とする場合には

余分なパラメータを使用してメソッドを作成し、インタフェースに追加することができます。これの1つの形式は、メソッドが必要とする追加のパラメータ値を導出するために使用できるさまざまなプロパティ/メソッドを持つオブジェクトを渡すことです。特別なケースは、呼び出し元が自身(この場合はクライアント)を渡してからCreateメソッドの内側から呼び出されるDouble Dispatchです。

あなたがこのアプローチを実装しながら、あなたはClientが暗黙のうちに、その後に構築されている特定のタイプを知っているし始めているという感覚を得るために開始するので、もし目標は、抽象的にIPacketが作成されてのタイプであることを覚えておく必要があり
//in MessageFactory : the PacketContext holds various data that may be relevant to creation 

public IPacket Create(Client creator, DateTime creationTime, string data, PacketContext ctx) 
{ 
    return new Message(creator, creationTime, data, ctx.SomeExtraData); 
} 

//in LogFactory: the Log doesn't need anything from the PacketContext but it does call something on the Client (Double Dispatch) 

public IPacket Create(Client creator, DateTime creationTime, string data, PacketContext ctx) 
{ 
    return new Log(creator.Name, creationTime, data); 
} 

一歩踏み込んで工場が適切であるかどうかを検討しなければならないかもしれません。あなたの他の唯一のオプションは、あなたがファクトリを構築するとき(つまりそれをコンストラクタに渡すとき)に追加の情報を提供することです。

public class MessageFactory : IPacketFactory 
{ 
    private object _data; 

    public MessageFactory(object extraData) 
    { 
     _data = extraData; 
    } 

    IPacket CreatePacket(Client creator, DateTime creationTime, string data) 
    { 
     return new Message(creator, creationTime, data, _extraData); 
    } 

    ///rest of implementation 
} 

者はオプションのいくつかを表しますが、いずれにしても、私は強く、それが工場に強く、カップル、あなたのクライアントクラスになり、ほとんどのため、あなたは、静的またはシングルトン「ファクトリー」クラスを使用しないことを助言しますおそらくIPacketサブクラスです。

+0

良い解決策ですが、私は他の2つのパラメータを持つMessageFactoryなど、いくつかのコンストラクタを使いたいと思っています。どのようにこれらの工場を建設すべきですか? – Saint

+0

@Saint - 新しいセクションが追加されました。 HTH。 –

+0

すばらしい答え!工場のパターンを理解するのに役立ちました – MUG4N

3

IMOそれはCREATIONTIME、作成者、データは、パケットの有効なインスタンスを作成するために必要とされているかどうかによって異なります。もしそうなら、私は解決策1に固執し、可能な限り早い段階でそれらのプロパティを設定する必要があります。これらのプロパティーが後で変更されることになっていない場合は、これらのプロパティーを読み取り専用にします。 プロパティの設定がオプションの場合は、ファクトリインターフェイスをクリーンに保ち、プロパティを持つオーバーロードを削除します。

1

私は

  • あなたは読み取り専用として、すべてのIPacketのプロパティをマークすることができ、このようにbecuase最初のアプローチを示唆しているであろうと、すべてのインスタンスは不変となります
  • オブジェクトを構築するために必要なすべてのパラメータを渡すことが非常に明確ですCreate..()ファクトリメソッドではなく、仕事のウィッヒは工場に委任されている必要があり行うことで、後で自分でそれらのすべてを初期化する...

とaproachについてファクトリメソッドのパラメータとして - 抽象的なdoctypeでClientを実行してください。そうすれば、Creatorモックとファクトリを注入してこのファクトリをテストするのがはるかに柔軟になります。

概要:

  • キープは、工場出荷時に不変
  • Delegateオブジェクトの作成作業をオブジェクトと工場caleeの間でそれを分割していない、これはインタフェースによって
  • 抽象すべての入力パラメータコードが希望それほどきれいではありません結合が少なく、簡単にテストすることができます。
関連する問題