我没有使用.Net泛型的经验。我正在为.Net 4.0中的投资控股公司设计软件系统。该公司拥有零售业务和IntellectualRights业务。 BookShop和AudioCDShop是零售业务的例子。 EngineDesignPatent和BenzolMedicinePatent是IntellectualRights业务的例子。这两种业务类型完全不相关。
投资公司有一个名为InvestmentReturn的概念。这是从每个企业获得的利润。对于每个“业务类型”(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;
}
}
问题
如何在List<InvestmentReturnElement<IBusiness>>
函数中的Main
profitElements中添加各种业务元素?
注意:执行以下操作时出现编译错误 profitElements.Add(salesProfitBook);
如何以通用方式实现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);
}
}
更新
BookShop
,EngineDesignPatent
继承了不同的基类。因此,我无法将IBusiness
,IRetailBusiness
和IIntellectualRights
作为抽象类。它们应保持为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();
}
}
答案 0 :(得分: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:或者您可能会认为业务与利润计算的观点如此不同,以至于您将一种类型的列表与其他类型分开,并在没有泛型的情况下处理它们。
答案 1 :(得分: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();
考虑到公式与目标接口相关联,这就像DRY一样。
答案 2 :(得分:0)
以下是基于Refactoring Code to avoid Type Casting
中来自@Kit的第一个回复的解决方案它可以避免在泛型的帮助下进行任何类型检查。
计算器抽象
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();
}