Suppose I have a class modeling expense items, named Expense. We have transportation, food, and wage expenses. Let's say that all of the properties are the same, so there is only the one Expense class, with a "type" property. However, let's say I add a new type of expense, called training, and this requires some new fields about the type of training, location, and date occurred. Additionally, there are a couple new methods specific to this training expense. So at this point, I need to subclass the Expense class so that I can have a TrainingExpense class. As the subclass is now defining the type of expense, does this make it redundant to have a "type" property in the Expense base class? Should I now just subclass the Expense base class for every different type? Or should I just leave the "type" property in the base class and have it be redundant for any subclasses?
Instead of inheritance I would use composition here. Create a property say ExpenseExtension of type interface IExpenseExtension
in the base class.
For the expense types that have extra properties/methods inherit from IExpenseExtension and add the extra properties/methods needed. In the TravelExpense case it will have a TravelExpenseExtension
class that inherits from IExpenseExtension with the extra properties/methods you need.
In the base class instantiate the appropriate ExpenseExtension
class based on the ExpenseType
Property.
Using composition instead of inheritance here will make it more flexible.
I would also suggest you to create an enum with all the types and use it for the ExpenseType property.
Check below Url to read about composition vs inheritance:
http://lostechies.com/chadmyers/2010/02/13/composition-versus-inheritance/
From the link: Favoring object composition over class inheritance helps you keep each class encapsulated and focused on one task. Your classes and class hierarchies will remain small and will be less likely to grow into unmanageable monsters.
UPDATE: See below code example in C#:
public class Expense
{
public string Food { get; set; }
public ExpenseType Type { get; set; }
private IExpenseExtension expenseExtension;
public IExpenseExtension ExpenseExtension
{
get
{
if(expenseExtension == null)
{
// Logic to instantiate the correct Extension based on Type property.
// You can use Factory design pattern or something like that for this as well.
}
return expenseExtension;
}
}
}
public interface IExpenseExtension
{
}
public class TrainingExpenseExtension : IExpenseExtension
{
public string Location { get; set; }
public void GetTrainingDetails()
{
}
}
Another approach might be define an IExpense interface, and then implement, so all your "standard" behaviours are accessed through the interface and the special behaviours via the class. Composition approach like blacktie24's but inverted. All depends on how you are going to access the extra stuff.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With