I am not experienced in using .Net generics. I am designing a software system for and Investment Holding Company in .Net 4.0. The company has Retail business and IntellectualRights business. BookShop and AudioCDShop are examples of Retail business. EngineDesignPatent and BenzolMedicinePatent are examples of IntellectualRights business. These two business types are totally unrelated.
The investment company has a concept called InvestmentReturn. It is the profit gained from each business. For each “Business Type” (Retail, IntellectualRights ), the calculation logic is different for Investment return.
I need to create a InvestmentReturnCalculator by calculating investment of each “Business Type”.
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;
}
}
QUESTION
How to add various business elements into
List<InvestmentReturnElement<IBusiness>>
profitElements in theMain
function ?Note: I am getting compilation error when I do the following profitElements.Add(salesProfitBook);
How to implement the GetNetInvestementReturn method in a generic way? If I make the code as follows, there is repetition of the algorithm for different types.. And generics can be used when algorithm is same for multiple types. So the following approach is not
DRY
.
Note: The following code does not compile.
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:
The BookShop
, EngineDesignPatent
inherits a different base class. So I cannot make IBusiness
, IRetailBusiness
, and IIntellectualRights
as abstract classes. They should remain as interfaces
.
Now @Grzenio suggestion is to implement a GetInvestmentProfit
method in each entity (BookShop, AudioCDShop, etc). Here I will be repeating the same code. Again this is not satisfying DRY
.
Moreover the InvestmentReturn
concept is for the investment holding company. The individual business types are unaware of such a concept.
Investment Return Element
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;
}
}
Business Type Abstractions
public interface IBusiness
{
}
public interface IRetailBusiness : IBusiness
{
bool IsOnSale { get; set; }
double Revenue { get; set; }
}
public interface IIntellectualRights : IBusiness
{
double Royalty { get; set; }
}
Concrete Businesses
#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
Client
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();
}
}