2014-01-30 33 views
3

我沒有使用.Net仿製藥的經驗。我正在爲.Net 4.0中的投資控股公司設計一個軟件系統。該公司擁有零售業務和IntellectualRights業務。 BookShop和AudioCDShop是零售業務的例子。 EngineDesignPatent和BenzolMedicinePatent是IntellectualRights業務的例子。這兩種業務類型完全無關。如何使用泛型實現此功能?

該投資公司有一個名爲投資回報的概念。這是從每項業務中獲得的利潤。對於每個「業務類型」(Retail,IntellectualRights),投資回報的計算邏輯都不相同。

我需要通過計算每個「業務類型」的投資來創建一個InvestmentReturnCalculator。

public static class InvestmentReturnCalculator 
{ 
    public static double GetNetInvestementReturn(List<IBusiness> allMyProfitableBusiness, List<InvestmentReturnElement<IBusiness>> profitElements) 
    { 
     double totalReturn = 0; 
     foreach (IBusiness b in allMyProfitableBusiness) 
     { 
      //How to do calculation? 
     } 
     return totalReturn; 
    } 
} 

問題

  1. 如何不同的業務元素添加到List<InvestmentReturnElement<IBusiness>> profitElements在Main功能?

    注意:我在執行以下操作時遇到編譯錯誤 profitElements.Add(salesProfitBook);

  2. 如何以通用方式實現GetNetInvestementReturn方法?如果我的代碼如下所示,不同類型的算法會有重複。對於多種類型,算法相同時可以使用泛型。所以下面的方法不是DRY

注意:下面的代碼不能編譯。

foreach (IBusiness b in allMyProfitableBusiness) 
    { 
     if (b is IRetailBusiness) 
     { 
      RetailProfit<IRetailBusiness> retailInvestmentProfit = new RetailProfit<IRetailBusiness>(); 
      totalReturn = totalReturn + retailInvestmentProfit.GetInvestmentProfit(b); 
     } 
     else if (b is IIntellectualRights) 
     { 
      IntellectualRightsProfit<IIntellectualRights> intellectualRightsInvestmentProfit = new IntellectualRightsProfit<IIntellectualRights>(); 
      totalReturn = totalReturn + intellectualRightsInvestmentProfit.GetInvestmentProfit(b); 
     } 
    } 

UPDATE:

BookShopEngineDesignPatent繼承的不同的基類。所以我不能將IBusinessIRetailBusinessIIntellectualRights作爲抽象類。他們應該保持爲interfaces

現在@Grzenio建議在每個實體(BookShop,AudioCDShop等)中實施GetInvestmentProfit方法。在這裏,我將重複相同的代碼。這再次不令人滿意DRY

此外InvestmentReturn概念是爲投資控股公司。各種業務類型都不知道這樣的概念。

投資回報元素

public abstract class InvestmentReturnElement<T> 
    { 
     public abstract double GetInvestmentProfit(T obj); 
    } 

    public class RetailProfit<T> : InvestmentReturnElement<T> where T : IRetailBusiness 
    { 
     public override double GetInvestmentProfit(T item) 
     { 
      return item.Revenue * 5/100; 
     } 
    } 

    public class IntellectualRightsProfit<T> : InvestmentReturnElement<T> where T : IIntellectualRights 
    { 
     public override double GetInvestmentProfit(T item) 
     { 
      return item.Royalty * 10/100; 
     } 
    }  

企業類型抽象

public interface IBusiness 
{ 

} 

public interface IRetailBusiness : IBusiness 
{ 
    bool IsOnSale { get; set; } 
    double Revenue { get; set; } 
} 

public interface IIntellectualRights : IBusiness 
{ 
    double Royalty { get; set; } 
} 

混凝土企業

#region Intellectuals 
    public class EngineDesignPatent : IIntellectualRights 
    { 
     public double Royalty { get; set; } 
    } 

    public class BenzolMedicinePatent : IIntellectualRights 
    { 
     public double Royalty { get; set; } 
    } 
    #endregion 

    #region Retails 
    public class BookShop : IRetailBusiness 
    { 
     public bool IsOnSale { get; set; } 
     public double Revenue { get; set; } 
    } 

    public class AudioCDShop : IRetailBusiness 
    { 
     public bool IsOnSale { get; set; } 
     public double Revenue { get; set; } 
    } 
    #endregion 

客戶

class Program 
    { 

     static void Main(string[] args) 
     { 

      #region MyBusines 

      List<IBusiness> allMyProfitableBusiness = new List<IBusiness>(); 

      BookShop bookShop1 = new BookShop(); 
      AudioCDShop cd1Shop = new AudioCDShop(); 
      EngineDesignPatent enginePatent = new EngineDesignPatent(); 
      BenzolMedicinePatent medicinePatent = new BenzolMedicinePatent(); 

      allMyProfitableBusiness.Add(bookShop1); 
      allMyProfitableBusiness.Add(cd1Shop); 
      allMyProfitableBusiness.Add(enginePatent); 
      allMyProfitableBusiness.Add(medicinePatent); 

      #endregion 

      List<InvestmentReturnElement<IBusiness>> profitElements = new List<InvestmentReturnElement<IBusiness>>(); 

      var salesProfitBook = new RetailProfit<BookShop>(); 
      var salesProfitAudioCD = new RetailProfit<AudioCDShop>(); 
      var intellectualProfitEngineDesign = new IntellectualRightsProfit<EngineDesignPatent>(); 
      var intellectualProfitBenzolMedicine = new IntellectualRightsProfit<BenzolMedicinePatent>(); 

      //profitElements.Add(salesProfitBook); 
      Console.ReadKey(); 
     } 

    } 
+3

爲了實現這一點,你是對的,現在你需要使用反射來確定類型和調用正確的方法。更好的解決方案是使用像GetProfit這樣的方法創建一個通用接口,並使每個業務對象繼承此接口並實現GetProfit,但是您需要在每個業務中使用該接口。 – Phaeze

+0

_在這裏我將重複相同的代碼。再次,這不令人滿意DRY._我不同意這一點。如果每個實體的公式不同(即使只是略有不同),那麼您的設計仍然是乾的。 –

+0

可以在Eric Lippert的博客中找到類似[Curiously Recurring Template Pattern](http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx)的幫助嗎? – Lijo

回答

0

以下是在Refactoring Code to avoid Type Casting

基於從@Kit第一反應的解決方案。它避免了與仿製藥的幫助,任何類型的檢查。

enter image description here

計算器抽象

public abstract class InvestmentReturnCalculator 
{ 
    public double ProfitElement { get; set; } 
    public abstract double GetInvestmentProfit(); 

    protected double CalculateBaseProfit() 
    { 
     double profit = 0; 
     if (ProfitElement < 5) 
     { 
      profit = ProfitElement * 5/100; 
     } 
     else 
     { 
      profit = ProfitElement * 10/100; 
     } 
     return profit; 
    } 
} 

public abstract class InvestmentReturnCalculator<T> : InvestmentReturnCalculator where T : IBusiness 
{ 
    public T BusinessType { get; set; } 
} 

混凝土計算器

public class RetailInvestmentReturnCalculator : InvestmentReturnCalculator<IRetailBusiness> 
{ 
    public RetailInvestmentReturnCalculator(IRetailBusiness retail) 
    { 
     BusinessType = retail; 
     //Business = new BookShop(100); 
    } 

    public override double GetInvestmentProfit() 
    { 
     ProfitElement = BusinessType.GrossRevenue; 
     return CalculateBaseProfit(); 
    } 
} 

public class IntellectualRightsInvestmentReturnCalculator : InvestmentReturnCalculator<IIntellectualRights> 
{ 

    public IntellectualRightsInvestmentReturnCalculator(IIntellectualRights intellectual) 
    { 
     BusinessType = intellectual; 
    } 

    public override double GetInvestmentProfit() 
    { 
     ProfitElement = BusinessType.Royalty; 
     return base.CalculateBaseProfit(); 
    } 
} 

業務抽象

public interface IBusiness 
{ 
    InvestmentReturnCalculator GetMyInvestmentReturnCalculator(); 
} 

public abstract class EntityBaseClass 
{ 

} 

public interface IRetailBusiness : IBusiness 
{ 
    double GrossRevenue { get; set; } 
} 

public interface IIntellectualRights : IBusiness 
{ 
    double Royalty { get; set; } 
} 

混凝土企業

public class EngineDesignPatent : EntityBaseClass, IIntellectualRights 
{ 
    public double Royalty { get; set; } 
    public EngineDesignPatent(double royalty) 
    { 
     Royalty = royalty; 
    } 

    public InvestmentReturnCalculator GetMyInvestmentReturnCalculator() 
    { 
     return new IntellectualRightsInvestmentReturnCalculator(this); 
    } 
} 

public class BookShop : EntityBaseClass, IRetailBusiness 
{ 
    public double GrossRevenue { get; set; } 
    public BookShop(double grossRevenue) 
    { 
     GrossRevenue = grossRevenue; 
    } 

    public InvestmentReturnCalculator GetMyInvestmentReturnCalculator() 
    { 
     return new RetailInvestmentReturnCalculator(this); 
    } 
} 

public class AudioCDShop : EntityBaseClass, IRetailBusiness 
{ 
    public double GrossRevenue { get; set; } 
    public AudioCDShop(double grossRevenue) 
    { 
     GrossRevenue = grossRevenue; 
    } 

    public InvestmentReturnCalculator GetMyInvestmentReturnCalculator() 
    { 
     return new RetailInvestmentReturnCalculator(this); 
    } 

} 

客戶

static void Main(string[] args) 
    { 

     #region MyBusines 

     List<IBusiness> allMyProfitableBusiness = new List<IBusiness>(); 

     BookShop bookShop1 = new BookShop(75); 
     AudioCDShop cd1Shop = new AudioCDShop(80); 
     EngineDesignPatent enginePatent = new EngineDesignPatent(1200); 
     BenzolMedicinePatent medicinePatent = new BenzolMedicinePatent(1450); 

     allMyProfitableBusiness.Add(bookShop1); 
     allMyProfitableBusiness.Add(cd1Shop); 
     allMyProfitableBusiness.Add(enginePatent); 
     allMyProfitableBusiness.Add(medicinePatent); 

     #endregion 

     var investmentReturns = allMyProfitableBusiness.Select(bus => bus.GetMyInvestmentReturnCalculator()).ToList(); 

     double totalProfit = 0; 
     foreach (var profitelement in investmentReturns) 
     { 
      totalProfit = totalProfit + profitelement.GetInvestmentProfit(); 
      Console.WriteLine("Profit: {0:c}", profitelement.GetInvestmentProfit()); 
     } 

     Console.ReadKey(); 
    } 
1

回答您的問題

(1)嘗試使InvestmentReturnElement逆變(和所有的繼承人):

public abstract class InvestmentReturnElement<in T> 
{ 
    public abstract double GetInvestmentProfit(T obj); 
} 

(2)我可能是錯的,但我不認爲有可能神奇般地創建InvestmentReturnElement<T>參數化爲調用類型,當您在調用它時靜態不知道T

選項1:要麼你可以使企業級計算其利潤

public interface IBusiness 
{ 
    double Profit {get;} 
    double OtherProfit (SomeCalculatorObject o); 
} 

選項2:或者,你可能會認爲該企業從利潤計算的角度如此不同,你將保持與其他類型分開的一種類型的列表,並且在沒有泛型的情況下處理它們。

+0

獲取編譯錯誤:「無效的方差修改器。只有接口和委託類型參數可以被指定爲variant.' – Lijo

1

雖然我想不出使用泛型的解決方案,我認爲這是你想要什麼:

public abstract class InvestmentReturnElement 
{ 
    protected InvestmentReturnElement(IBusiness business) 
    { 
     this.Business = business; 
    } 

    public IBusiness Business { get; private set; } 

    public abstract double GetInvestmentProfit(); 
} 

public class RetailProfit : InvestmentReturnElement 
{ 
    public RetailProfit(IRetailBusiness retailBusiness) 
     : base(retailBusiness) 
    { 
    } 

    public override double GetInvestmentProfit() 
    { 
     return ((IRetailBusiness)this.Business).Revenue * 5/100; 
    } 
} 

public class IntellectualRightsProfit : InvestmentReturnElement 
{ 
    public IntellectualRightsProfit(IIntellectualRights intellectualRightsBusiness) 
     : base(intellectualRightsBusiness) 
    { 
    } 

    public override double GetInvestmentProfit() 
    { 
     return ((IIntellectualRights)this.Business).Royalty * 10/100; 
    } 
} 

客戶

List<InvestmentReturnElement> profitElements = new List<InvestmentReturnElement>(); 

var salesProfitBook = new RetailProfit(bookShop1); 
var salesProfitAudioCD = new RetailProfit(cd1Shop); 
var intellectualProfitEngineDesign = new IntellectualRightsProfit(enginePatent); 
var intellectualProfitBenzolMedicine = new IntellectualRightsProfit(medicinePatent); 

profitElements.Add(salesProfitBook); 
profitElements.Add(salesProfitAudioCD); 
profitElements.Add(intellectualProfitEngineDesign); 
profitElements.Add(intellectualProfitBenzolMedicine); 

foreach (var profitelement in profitElements) 
{ 
    Console.WriteLine("Profit: {0:c}", profitelement.GetInvestmentProfit()); 
} 

Console.ReadKey(); 

這是因爲幹它會得到,考慮到公式與目標接口綁定。