2016-12-07 3 views
0

これは設計上の問題です。より具体的には、これを行うより良い方法があるかどうか疑問に思っていました。基本的には、さまざまな種類の休暇(有料、未払いなど)がさまざまな企業で計算できる電卓の実装では、 を実装しています。各企業は、四捨五入、日/日などのような独自のひねりを持つ傾向があります。さまざまなコンセプトを持つこのファクトリクラスのデザインを改善するにはどうすればよいですか?

計算機は異なるコードにバインドされており、特定の企業にバインドされています(コードAFirmOne) - 私のデザインではありませんが、私はこれらを尊重しなければなりません。

簡略化した例:実際に

internal class CalculatorFactory 
{ 
    internal ICalculator Create(string calculatorCode) 
    { 
     ICalculator result; 
     switch (calculatorCode) 
     { 
      case FirmOne.CalculatorCodes.A: 
      case FirmTwo.CalculatorCodes.B: 
       result = new FastCalculator(); 
       break; 
      case FirmOne.CalculatorCodes.X: 
      case FirmTwo.CalculatorCodes.Y: 
       result = new SlowCalculator(); 
       break; 
      case FirmThree.CalculatorCodes.Z: 
       result = new VerySlowCalculator(); 
       break; 
      default: 
       throw new NotSupportedException(); 
     } 

     return result; 
    } 
} 

internal interface ICalculator 
{ 
    decimal Calculate(); 
} 

がしっかりあたりダース異なる計算程度であるので、私は工場上記 に作成ロジックを抽出する代わりに、あらゆる場所にスイッチケースでコードを散らかすのクラス。近い将来にもっと多くの計算機が追加される可能性があることを念頭に置いて、この設計を改善する方法を提案する人はいますか?

特に文字列として渡されたコードが好きではないので、最初の改善点は列挙型にすることができますが、それ以外は..?おそらく会社ごとに別々の工場を作るのですか?

ありがとうございます!

+1

なぜコードレビューコミュニティでこの質問をしませんでしたか? – Badiparmagi

+1

これは、コードよりもパターンに関するコードレビューではなく、ソフトウェアエンジニアリングに適しています。 – toadflakz

+1

私はソフトウェアエンジニアリングSEに移行する必要があるので、この質問を議論の対象外とすることに投票しました。質問はパターンではなくコードであるため、Code Review SEへの移行を提案していません。 – toadflakz

答えて

2

私の意見では、お互いを排除しないという2つの選択肢があります。最初にDictionar<string, Type>を選択するか、代わりにDictionary<string, Func<ICalculator>>にコードとタイプまたはコンストラクタを格納してインスタンスrepsectivlyを作成することができます。後者here's例えば:

var types = new Dictionary<string, Func<ICalculator>> 
{ 
    { "A", new Func<ICalculator>(() => new FastCalculator()), 
    { "B", new Func<ICalculator>(() => new FastCalculator()), 
    { "X", new Func<ICalculator>(() => new SlowCalculator()), 
}; 

代わりの反射に頼ってあなたのタイプのインスタンスを作成するためにこれを使用することもできます。

var newInstance = types["A"](); 

他のオプションは、設定ファイルを使用することです可能なすべてのタイプを指定することができます。ここでファイルを読み、そのファイル内のすべての名前に1つのタイプを割り当てます。

<type code="A" name="MyNamespace.FastCalculator" /> 
<type code="B" name="MyNamespace.FastCalculator" /> 
<type code="X" name="MyNamespace.SlowCalculator" /> 

今すぐ簡単にリフレクションを使用してこれらの型のインスタンスを作成することができます。もちろん

var myInstance = Activator.CreateInstance(type.Name) as ICalculator; 

あなたはまたしても種類やFunc<ICalculator>を使用してコンストラクターthemselfesをキャッシュするためにここにDictionaryを選ぶことができます。

第2の方法は変更がより多くあります。特に、新しいタイプを追加するときに工場コードを変更する必要はありません。

+0

多分私は私の質問でより具体的でなければならなかった、すべての計算機は、アプリケーションのすべての実行のために使用されます。基本的には、異なる会社の従業員を処理する予定の仕事です。従業員の会社によっては、異なる計算機セットが使用されます。あなたは一般的に辞書を使用することについてどのように感じますか?私は助けることができませんが、これは漏れ抽象であると感じています - 呼び出し側に実装に関するいくつかの詳細を知らせるようにします(コードなど)。 – rumblefx0

+0

変更のために開いたままにするには、新しい電卓ごとに列挙を変更する必要があるため、列挙型は悪い選択です。しかし抽象的なファクトリーを選ぶこともできます。https://en.wikipedia.org/wiki/Abstract_factory_patternをご覧ください。ここでは、各企業ごとに1つの工場があります。 – HimBromBeere

+0

それは私が移動していた方向だった。あなたはまだ工場ごとに大きなスイッチを持っていますが、あなたはどこかのタイプのものを使用するという決定を下す必要があります。 – rumblefx0

2

calculatorCodeを定義するために使用できるカスタムのAttributeクラスを作成することを考えていました。

ICalculatorの実装をその属性で飾ることができます。アプリケーションの起動時、またはCalculatorFactoryの初期化時には、すべてのICalculatorタイプを検査し、特定の電卓コード用にインスタンス化する特定のICalculatorタイプを保持する辞書を作成することができます。

工場は、特定のコードで使用するタイプを検索し、そのタイプのインスタンスを作成します。

このような何か:

[CalculatorCode("xyz")] 
[CalculatorCode("foo")] 
public class FastCalculator : ICalculator { ... } 


public static class CalculatorFactory 
{ 

    private static Dictionary<string, Type> _calcDictionary = new Dictionary<string, Type>(); 

    static CalculatorFactory() 
    { 
     var calctypes = Assembly.GetExecutingAssembly()GetTypes().Where(t => t.IsAssignableFrom(typeof(ICalculator))).ToList(); 

     foreach(var ct in calctypes) 
     { 
      var attributes = (CalculatorCodeAttribute[])Attribute.GetCustomAttributes (ct, typeof (CalculatorCodeRuleAttribute)); 

      foreach(var attr in attributes) 
      { 
       // add the info to a dictionary 
       _calcDictionary.Add(attr.CalculatorCode, ct); 
      } 
     } 


    } 

    public static ICalculator Create(string calcCode) 
    { 
     if(_calcDictionary.ContainsKey(calcCode) == false) 
     { 
       throw new ArgumentException("No ICalculator defined for the given code"); 
     } 

     return _calcDictionary[calcCode]; 
    } 

} 

There might be syntax errors or imperfections in the code above. It is just to g 

はあなたに私は大きなswitch文を取り除くために、この操作を行うような方法のアイデアをアイブ。

さらに拡張性を高めるために、Microsoft Extensibility Frameworkをご覧ください。

+0

面白い実装では、私は避けたいと思っている(属性を介して)さまざまなクラスに渡ってすべての電卓コードを広げることになると思います。 – rumblefx0

+1

別の方法は、中央の場所で何らかのレジストリを追跡することです。たとえば、Factoryクラスの辞書に自分自身を埋め込むことができます。 –

0

利用可能なさまざまなDIコンテナを使用できます。 Autofac、Unity、Ninjectなど コンクリートをコードやXML構成からインターフェイスにブートストラップすることができます。

DIフレームワークを使用することで(独自のコードを書くことができます)、ファクトリメソッドだけでなく、コードの構造や変更をよりオープンにすることができます。

関連する問題