I wrote the bottom level classes of multilevel inherited class but confused how to combine them to a single program. Someone suggested me to use composition instead of inheritance, and someone suggested to use enum
to create anonymous subclass instead of complex inheritance structure. How can we use composition in place of inheritance or use enum
instead of the inheritance that I used? What Should I do to simplify problem and How should it be done?
I am using Java to write a code to calculate tax. I am having base class TaxPayer
. Taxpayer can have multiple incomeSource
. There can be many types of TaxPayer
or IncomeSource
. There can be many income headings for each income source which is used to calculate taxableIncome
. taxRate
will be different for different type of taxPayer
and taxableIncome
. Final result will be taxRate
applied to taxableIncome
.
Base class Taxpayer is defined as
public abstract class TaxPayer {
private List<IncomeSource> incomeSource;
double taxRate;
Address address;
other attributes here;
public Double getTaxRate(){
return 0.25; //default tax rate
}
}
public abstract class IncomeSource {
private String incomeSourceName;
private Double incomeHeading1, incomeHeading2, incomeHeading3, ...;
private Double taxableIncome = incomeHeading1 + incomeHeading2 - incomeHeading3;
}
There can be some subclass of IncomeSource
with different income headings. Similarly tax payer type can be modeled into following inheritance structure
Base Class: Taxpayer
* IndividualPerson
* Male, Female, OldAge
* Business
* Bank, ITIndustry, HydroElectricIndustry
* TaxFree
* SocialOrganization, ReligiousOrganization, PoliticalParty etc.
The subclasses of TaxPayer
generally modifies the taxRate
to be applied to taxableIncome
and sometimes changes taxableIncome
with some logic. For an example:
abstract class IndividualPerson extends TaxPayer{
if (incomeSource.taxableIncome > 250000) taxRate = ratex;
if (incomeSource.taxableIncome > 500000) taxRate = ratey;
@override
public getTaxRate() {
return taxRate;
}
}
class Female extends IndividualPerson {
if (incomeSource.getNumberOfIncomeSource() > 1) taxRate = taxRate + rate1;
else taxRate = taxRate - rate2
if (address.isRural() = true) taxRate = taxRate - rate3;
if (attributeX = true) taxRate = taxRate + rate4;
if ("Some other attribute" = true) taxableIncome = taxableIncome - someAmount;
}
We have to check attributes of Taxpayer
and IncomeSource
to determine the taxRate
. Sometimes, taxableIncome
can be modified according to taxPayer
type and other conditions.
I am confused how to combine bottom level classes together to make a useable code. Someone suggested me not to use complex multilevel inheritance, instead, use composition or enum
to achieve the desired result with less complexity. How to do this? Please give answers with enough details for beginners to understand.
Ok, i wont program your case out, but i will give you some guidlines to what composition is, and how to solve it with enums. Your problem seems to be, that you have a TaxPayer, and the only thing that is shared, is the default tax rate.
With composition, instead of using inheritance, you have a instance of TaxPayer in your class:
public class TaxPayer {
private List<IncomeSource> incomeSource;
double taxRate;
Address address;
other attributes here;
public Double getTaxRate(){
return 0.25; //default tax rate
}
}
public class Male {
private TaxPayer taxPayer = new TaxPayer();
public Double getTaxRate(){
return taxPayer.getTaxRate();
}
}
So instead of abstraction, you link the methods through that you want to use of TaxPayer.
With enums the solution would probally look something like this:
public enum TaxPayer {
MALE,
FEMALE {
public Double getTaxRate(){
return 1; //custom tax rate
}
};
public Double getTaxRate(){
return 0.25; //default tax rate
}
}
Now you can use:
TaxPayer.MALE.getTaxRate();
in your code!
A third option would be defining an interface and define the defaultTaxRate as a constant.
public interface TaxPayer {
Double getTaxRate();
}
public class Male implements TaxPayer {
public Double getTaxRate(){
return Constants.DEFAULT_TAX_RATE;
}
}
public class Constants {
public static final double DEFAULT_TAX_RATE = 0.25;
}
And now for the important bit, why would you any of these over extention.
First off, you can only extend 1 class, so it makes your class less versitile, and harder to use. The enum and interface solve this for you (since you can still apply the Strategy Pattern to it).
public void foo(TaxPayer anyImplementationOfTaxPayer){
bar(anyImplementationOfTaxPayer.getTaxRate());
}
As you see, by using an interface or an enum, its far more extendible than an abstract class.
Secondly, if you add a method to the abstract class, ALL the classes that extend from it will inherit this method, and are forced to deal with/implement behaviour of this extra method, or have a partly unusable API.