2009-03-30 5 views
2

更新済み私は私の問題をよりよく説明するために例を更新しました。つまり、​​メソッドが常にラベルタイプを取り、ファクトリがどのタイプのラベルを作成するかを決めることができるということです。つまり、返されるラベルの種類に応じて、より多くの情報を取得する必要があるかもしれません。工場のクラスはあまりにも多くを知っています

私はプリンタに送るラベルを表すオブジェクトを返すファクトリクラスを持っています。

ファクトリクラスは次のようになります。

public class LargeLabel : ILabel 
{ 
    public string TrackingReference { get; private set; } 

    public LargeLabel(string trackingReference) 
    { 
     TrackingReference = trackingReference; 
    } 
} 

public class SmallLabel : ILabel 
{ 
    public string TrackingReference { get; private set; } 

    public SmallLabel(string trackingReference) 
    { 
     TrackingReference = trackingReference; 
    } 
} 

public class LabelFactory 
{ 
    public ILabel CreateLabel(LabelType labelType, string trackingReference) 
    { 
     switch (labelType) 
     { 
      case LabelType.Small: 
       return new SmallLabel(trackingReference); 
      case LabelType.Large: 
       return new LargeLabel(trackingReference); 
     } 
    } 
} 

は私がCustomLabelと呼ばれる新しいラベルタイプを、作成することを言います。私は工場からこれを返すようにしたいが、それはいくつかの追加データを必要とします:

public class CustomLabel : ILabel 
{ 
    public string TrackingReference { get; private set; } 
    public string CustomText { get; private set; } 

    public CustomLabel(string trackingReference, string customText) 
    { 
     TrackingReference = trackingReference; 
     CustomText = customText; 
    } 
} 

これは私のファクトリメソッドを変更する必要がありますを意味します

public class LabelFactory 
{ 
    public ILabel CreateLabel(LabelType labelType, string trackingReference, string customText) 
    { 
     switch (labelType) 
     { 
      case LabelType.Small: 
       return new SmallLabel(trackingReference); 
      case LabelType.Large: 
       return new LargeLabel(trackingReference); 
      case LabelType.Custom: 
       return new CustomLabel(trackingReference, customText); 
     } 
    } 
} 

工場が今必要とするので、私はこれが好きではありません最も低い共通分母に対応しますが、カスタムテキスト値を取得するには、同時にCustomLabelクラスにはが必要です。追加のファクトリメソッドをオーバーライドとして提供することもできますが、CustomLabelに値が必要であるという事実を強制したい、そうでなければ空の文字列しか与えられません。

このシナリオを実装する正しい方法は何ですか?

+0

これは私がここで質問しようとしていたのと同じ質問だと思う:http://stackoverflow.com/questions/5562051/how-to-provide-a-plug-in-model-where-different-plug-ins- take-different-parameters –

答えて

5

どのようにしたいですかファクトリメソッドを呼び出しますか?

あなたのAPIをどのように使いたいかに集中し、実装は通常、それ自体がかなり明確になります。 APIの目的の結果を単体テストとして記述すると、これはさらに簡単になります。

ここでは過負荷が適切かもしれませんが、どのように工場を使いたいかによって決まります。

+2

問題は、パラメータに基づいて、どのラベルを返すかを工場が決めてほしいということです。問題は、戻したいラベルに応じて、追加情報が必要な場合があるということです。コールコードはファクトリを推測することができないので、この追加情報を渡す必要があることはわかりません。したがって、ファクトリが必要な情報を取得できない膠着状態にありますが、それを供給する必要があることを知っている。 –

1

これはおそらく、工場パターンがあなたにとって最適ではないことを示しています。あなたがそれを必要とするか、それに固執したい場合は、文字列ではなく、ファクトリに渡すことができる初期化クラス/構造体を作成することをお勧めします。基本情報クラスのさまざまなサブクラス(基本的に、ラベルクラスのそれを模倣する初期化クラス階層を作成する)、またはすべての情報を含む1つのクラスを使用するかどうかは、あなた次第です。

+0

代わりに、より適切なパターンを推奨できますか? –

+0

あなたの特定の環境を知らない私は、ラベル自体をインスタンス化するクライアントコードにどのような問題があるのだろうかと思います。言い換えれば、何が工場のパターンの道を導いたのですか? –

1

構成クラスを使用して、そのインスタンスを工場に渡すようにしてください。構成クラスは階層を構築します。ここでは、特別な構成クラスが、ファクトリから期待される結果ごとに存在します。各構成クラスは、ファクトリ結果の特定のプロパティを取得します。

私が与えた例では、BasicLabelConfigurationとそれから派生したCustomLabelConfigurationを記述します。 BasicLabelConfigurationは追跡参照を取得し、CustomLabelConfigurationはカスタムテキストを取得します。

最後に、工場は、渡された構成オブジェクトのタイプに基づいて決定します。ここで


はコードの例です:それはさらに情報がない

// Create basic label 
ILabel label = factory.CreateLabel(new BasicLabelConfiguration 
{ 
    TrackingReference = "the reference" 
}); 

または

// Create basic label 
ILabel label = factory.CreateLabel(new CustomLabelConfiguration 
{ 
    TrackingReference = "the reference", 
    CustomText = "The custom text" 
}); 
+0

うわー!これは複雑な方法です。 Adam Robinsonと同様に、基本的な実装のAPIのすべての複雑さを少なくとも複雑な(それ以上ではない)「構成」APIで公開すると、工場を使う利点は全くありません。 – Guss

+0

工場は依然として実際のオブジェクトの構築を担当しています。設定は、実際のオブジェクトを作成するための基本的なメンメントです。しかし、私はこれが複雑であることに同意します。 プロトタイプパターンを使用することもできますが、autherは自分の環境を記述していないため、適用可能かどうかわかりません。 – grover

1

public class BasicLabelConfiguration 
{ 
    public BasicLabelConfiguration() 
    { 
    } 

    public string TrackingReference { get; set; } 
} 

public class CustomLabelConfiguration : BasicLabelConfiguration 
{ 
    public CustomLabelConfiguration() 
    { 
    } 

    public string CustomText { get; set; } 
} 

public class LabelFactory 
{ 
    public ILabel CreateLabel(BasicLabelConfiguration configuration) 
    { 
    // Possibly make decision from configuration 
    CustomLabelConfiguration clc = configuration as CustomLabelConfiguration; 
    if (clc != null) 
    { 
     return new CustomLabel(clc.TrackingReference, clc.CustomText); 
    } 
    else 
    { 
     return new BasicLabel(configuration.TrackingReference); 
    } 
    } 
} 

最後に、このような工場を使用したいです助言を与えるのはかなり難しいEが、工場出荷時のパターンは、あなたが実際にあなたが次のアプローチを試みることが必要なものであると仮定すると:

パックプロパティマップのいくつかの種類で必要な引数が(例えば、文字列を文字列にマップする)、それをファクトリのcreateメソッドの引数として渡します。よく知られているタグをマップのキーとして使用し、特殊なファクトリがマップされた値を抽出し、独自の好みに応じて解釈できるようにします。

これは、工場のパターンがここで正しいものではないことがわかった場合(またはその時)に、当面は1つの工場インタフェースを維持し、建築上の問題に対処することを少なくとも可能にします。

(ああ、あなたが本当にここファクトリパターンを使用したい場合、私は強くあなたはそれがプラグイン可能なそれぞれの新しいラベルタイプのファクトリを変更することを避けるために行うことをお勧め)。

2

Factoryメソッドを使用して、必要なラベルを決定するのはどうですか?

public class LabelFactory { 
    public ILabel CreateLabel(string trackingReference, string customText) { 
     return new CustomLabel(trackingReference, customText); 
    } 

    public ILabel CreateLabel(String trackingReference) { 
     return new BasicLabel(trackingReference); 
    } 
} 

あなたの工場はまだ(インターフェースでは、動的ロード機能を実装することができますが)各タイプについて知っている必要がありますが、クライアントが知る必要があることはほとんどあり - どのようなデータに基づいてが提供され、工場は生成正しい実装。

これは、説明した単純な問題に対する単純な解決策です。私は質問がより複雑な問題の過度の単純化であると仮定しますが、あなたの本当の問題が何であるか分からずに、複雑な解決策を設計したくないと思います。

1

パターンが適合しないシナリオにパターンを強制しようとしています。私はその特定のパターンをあきらめ、最も簡単な解決策を可能にする代わりに焦点を当てることを提案します。

私はこのケースでは、私はちょうど空/通常nullですが、ラベルはカスタムにする必要がある場合は、1つを設定できるカスタムテキスト用のテキストフィールドを持っている一つのクラス、ラベルを持っていると思います。それは簡単で、自明であり、メンテナンスプログラマーに悪夢を与えません。

+0

ラベルに10種類の新しいビヘイビアを追加したい場合はどうなりますか?私はそれが単一のクラスを使用して悪夢になるだろうと思う;)。 http://en.wikipedia.org/wiki/Open/closed_principle –

+1

その後、私は時間の要件を満たすコードをリファクタリングします。未来を予測しようとしないでください。コストがかかり、しばしば間違っています。 –

0

あなたの質問を読んでから、UIが情報を収集してから、適切なラベルを作成するように聞こえるように聞こえます。私は、私が開発したCAD/CAMアプリケーションでは異なるアプローチを採用しています。

起動時に、アプリケーションはファクトリメソッドを使用してラベルのマスターリストを作成します。 私のラベルの中には、互いの変種であるため、初期化パラメータがあります。たとえば、3種類のフラットパーツラベルがあります。他のユーザーはセットアップ時にユーザー定義または未知のパラメーターを持っています。

最初のケースでは、初期化はファクトリメソッド内で処理されます。そこで、必要なパラメータを渡すFlatPartLabelの3つのインスタンスを作成します。

2番目のケースでは、Labelインターフェイスにconfigureオプションがあります。これは、ラベルプリンタダイアログで呼び出され、設定パネルに入力されます。あなたの場合、これはトラッキング参照とCustomTextが渡される場所です。

私のラベルインターフェイスは、各ラベルタイプの一意のIDも返します。そのタイプのラベルを処理する特定のコマンドがあれば、アプリケーション内のラベルのリストをトラバースして、IDと一致するものを見つけ出し、特定のタイプのラベルにキャストしてから構成します。これは、特定のフラットパーツのラベルのみを印刷する場合に行います。

これは、ラベルに必要なパラメータで任意の複雑なものになる可能性があり、不要なパラメータで工場に負担をかけないことを意味します。

1

ANSWER QUESTION OF UPDATE次の更新 - 私はまだあなたが正しいとcreateLabelメソッドをオーバーロードでFactoryパターンを使用して、正しいことをしていると思いますBELOW

を参照してください。しかし、私は、LabelTypeをCreateLabelメソッドに渡すと、Factoryパターンを使用する点が失われていると思います。

重要な点:Factoryパターンの目的は、どの具体的なサブクラスをインスタンス化して戻すかを選択するロジックをカプセル化することです。呼び出しコードは、どの型をインスタンス化するかをFactoryに伝えてはいけません。その利点は、Factoryを呼び出すコードが将来、そのロジックの変更から保護され、また、新しいconcreteサブクラスを工場に追加することから保護されることです。すべての呼び出しコードは、FactoryとCreateLabelから返されたInterfaceの型に依存しています。

あなたは工場は現在、この擬似コードのようなものを見なければならない呼び出す時点で、あなたのコード内のロジック...

// Need to create a label now 
ILabel label; 
if(we need to create a small label) 
{ 
    label = factory.CreateLabel(LabelType.SmallLabel, "ref1"); 
} 
else if(we need to create a large label) 
{ 
    label = factory.CreateLabel(LabelType.LargeLabel, "ref1"); 
} 
else if(we need to create a custom label) 
{ 
    label = factory.CreateLabel(LabelType.CustomLabel, "ref1", "Custom text") 
} 

は...そう、あなたが明示的に作成するために、どのような工場を言っています。新しいラベルタイプがシステムに追加されるたびに、あなたがする必要がありますので、これは変更

  1. ...、新しいLabelType値
  2. 移動に対処し、新しいを追加するために工場出荷時のコード悪いですそうでなければ工場が呼ばれたどこにでも

しかし、LabelType値を選択するロジックを工場に移すと、これは避けられます。ロジックは他のすべてと一緒に工場でカプセル化されています。新しいタイプのラベルがシステムに追加された場合は、Factoryを変更するだけで済みます。ファクトリを呼び出す既存のコードはすべて同じままですが、大きな変更はありません。

現在の呼び出しコードが大きなラベルまたは小さなラベルが必要かどうかを判断するために使用するデータは何ですか?そのデータは、工場のCreateLabel()メソッドに渡す必要があります。

あなたの工場とラベルのクラスは次のようになります...

// Unchanged 
public class BasicLabel: ILabel 
{ 
    public LabelSize Size {get; private set} 
    public string TrackingReference { get; private set; } 

    public SmallLabel(LabelSize size, string trackingReference) 
    { 
     Size = size; 
     TrackingReference = trackingReference; 
    } 
} 



// ADDED THE NULL OR EMPTY CHECK 
public class CustomLabel : ILabel 
{ 
    public string TrackingReference { get; private set; } 
    public string CustomText { get; private set; } 

    public CustomLabel(string trackingReference, string customText) 
    { 
     TrackingReference = trackingReference; 
     if(customText.IsNullOrEmpty()){ 
      throw new SomeException(); 
     } 
     CustomText = customText; 
    } 
} 



public class LabelFactory 
{ 
    public ILabel CreateLabel(string trackingReference, LabelSize labelSize) 
    { 
     return new BasicLabel(labelSize, trackingReference); 
    } 

    public ILabel CreateLabel(string trackingReference, string customText) 
    { 
     return new CustomLabel(trackingReference, customText); 
    } 
} 

私はこれが便利です願っています。

関連する問題