5

私は、いくつかのルールを使用して自動車保険のいくつかの異なる価格を計算する、私が書いたコードを少し改善する方法を模索しています。これが私を悩ませている部分です:

public Insurance GetInsurance(CarData carData)
{
    var insurance = new Insurance();

    insurance.priceGeneral = this.CalculatePrice(new Car { BrandDealer = false, MonthPayment = false, CarData = carData });
    insurance.priceGeneralMonth = this.CalculatePrice(new Car { BrandDealer = false, MonthPayment = true, CarData = carData });
    insurance.priceBrandDealer = this.CalculatePrice(new Car { BrandDealer = true, MonthPayment = false, CarData = carData });
    insurance.priceBrandDealerMonth = this.CalculatePrice(new Car { BrandDealer = true, MonthPayment = true, CarData = carData });

    return insurance;
}

通常の価格(年払い)と月々の支払いの計算には大きな違いがあり、BrandDealerがtrueかfalseかによって、計算方法も異なることに注意してください。この変数を削除しようとしましたが、顧客はこれらのルールを要求しています。

一部のプロパティは「車」の実際のプロパティではないことを認識していますが、それもすぐにリファクタリングします。

私はこの計算を4回行っていることに悩まされており、将来的にはさらに多くのルールがあります。そして、次の新しいルールは、別のブール値とさらに2つの計算を追加します。

ここで見つけていない、使用すべき素敵なデザインパターンはありますか?

4

3 に答える 3

3

まず、現在の問題を解決しましょう。これは、繰り返し計算コードをクリーンアップする方法です。

まず、Stratgeyパターンを価格計算に適用して、計算のインターフェイスを定義し、さまざまな計算ロジックコードを新しいホームに移動する必要があります。

// calculation common interface
public interface IPriceCalculation 
{
   public InsurancePrice CalculatePrice(CarData data);   
}

// result from the calculation
public class InsurancePrice
{
   public string Description { get; set; }
   public decimal Price { get; set; }      
}


// concrete implementations 
public class BrandDealerMonthlyPaymentCalculation : IPriceCalculation
{
   public InsurancePrice CalculatePrice(CarData data)
   {
      // logic to perform calculation of BrandDealer = true, MonthPayment = true

      // just for example...
      return new InsurancePrice() 
      { 
         Description = "Policy price with a Brand dealer and monthly payments",
         Price = 250.25;
      };
   }
}

public class BrandDealerYearlyPaymentCalculation : IPriceCalculation
{
   public InsurancePrice CalculatePrice(CarData data)
   {
      // logic to perform calculation of BrandDealer = true, MonthPayment = false
   }
}

public class NonBrandDealerYearlyCalculation : IPriceCalculation
{
   public InsurancePrice CalculatePrice(CarData data)
   {
      // logic to perform calculation of BrandDealer = false, MonthPayment = false
   }
}

public class NonBrandDealerMonthlyCalculation : IPriceCalculation
{
   public InsurancePrice CalculatePrice(CarData data)
   {
      // logic to perform calculation of BrandDealer = false, MonthPayment = true
   }
}

計算を定義したら、それらをインストールします。GetInsuranceメソッドを定義するクラス(InsuranceFactoryと呼びます)内で、コンストラクターでこれを行います。これは、プロパティ、構成、DIなどを介してそれらをプッシュする別のクラスを介して行うことができますが、ctorは説明のために最も簡単です。

public class InsuranceFactory
{
   private List<IPriceCalculation> _priceCalculators = new List<IPriceCalculation>();

   public InsuranceFactory()
   {
      _priceCalculators.Add(new BrandDealerYearlyPaymentCalculation());
      _priceCalculators.Add(new BrandDealerMonthlyPaymentCalculation());
      _priceCalculators.Add(new NonBrandDealerYearlyCalculation());
      _priceCalculators.Add(new NonBrandDealerMonthlyCalculation());
      // easy to add more calculations right here...
   }

}

次に、上記のInsuranceFactoryクラスのGetInsuranceメソッドを再検討します。

public Insurance GetInsurance(CarData carData) 
{     
   var insurance = new Insurance();      

   // iterate the different pricing models and them to the insurance policy results

   foreach (IPriceCalculation calculator in _priceCalculators)
   {
      insurance.PriceOptions.Add(calculator.CalculatePrice(carData));
   }

   return insurance; 

} 

新しい計算を作成するたびにGetInsuranceメソッドを変更する必要がなくなったことに注目してください。同様に、結果を保険オブジェクト()内のリストに保存することにより、insurance.PriceOptionsInsuranceクラスも変更する必要がありません。UIコードは、そのリストを繰り返すことですべてのオプションを表示できます。この例は少し単純化されていますが、うまくいくはずです。

さて、私が予想できる2番目の問題について少しお話します。計算サブクラスが追加の順列を持ち始めると、クラスが爆発的に増加します。たとえば、現在、2つの要素(ブランドとPaySchedule)があり、それぞれに2つの選択肢があり、2 x 2=4のクラスがあります。しかし、3つの選択肢(Goor、Fair、Poor)を使用してCreditScoreを追加するとどうなりますか。次に、次のようになります。

GoodCreditBrandDealerYearlyPaymentCalculation
GoodCreditBrandDealerMonthlyPaymentCalculation
GoodCreditNonBrandDealerYearlyCalculation
GoodCreditNonBrandDealerMonthlyCalculation
FairCreditBrandDealerYearlyPaymentCalculation
FairCreditBrandDealerMonthlyPaymentCalculation
FairCreditNonBrandDealerYearlyCalculation
FairCreditNonBrandDealerMonthlyCalculation
PoorCreditBrandDealerYearlyPaymentCalculation
PoorCreditBrandDealerMonthlyPaymentCalculation
PoorCreditNonBrandDealerYearlyCalculation
PoorCreditNonBrandDealerMonthlyCalculation

これはここから悪化するだけです。これは、それが出てきた場合、それ自体の質問と回答の価値がありますが、注意する必要があります。このようになり始めたら、Calculationクラスをリファクタリングします。しかし、すばらしいのは、GetInsuranceのコードを変更する必要がないことです。

于 2012-05-21T20:53:23.137 に答える
0

あなたがする必要があるのはあなたの計算をより小さな要素に分割することです。共通のコードを見つけて地図に保存する必要があります。calc 1 = A * B+C.およびcalc2= A * C--bとしましょう

A、B、Cを1回だけ実行し、ハッシュマップに保存する必要があります。now calc 2 = hash.getOrAdd(A key)* hash.getOrAdd(C key)-hash.getOrAdd(C key)。

運が悪かったためにcomonコードが見つからない場合は、すべての計算を実行する必要があります。

于 2012-05-20T10:14:32.990 に答える
0

本当に際立っていることの 1 つは、計算するたびに 4 つの新しい Car オブジェクトを作成することです。それは完全に必要ですか?異なる BrandDealer/MonthlyPayment の組み合わせで事前に作成 (および保存) したものを 4 つ用意し、それらを使用して適切な CarData の受け渡しを計算できますか?

さらに、これは、必要なさまざまな Car オブジェクトとその他の計算の詳細を抽象化/非表示にする、ある種の計算ファクトリを使用してより適切に実現できる場合があります。計算の種類ごとに内部メソッドを追加することを検討してください。新しい計算では、1 つの大きなメソッドを変更するのではなく、別のメソッドを追加するだけで済みます。通常、これはメソッドの代わりに計算オブジェクトを追加することで実現できますが、この特定の状況ではやり過ぎかもしれません。

于 2012-05-20T11:25:58.693 に答える