Note: Download the source code from https://gitlab.com/som.mukhopadhyay/SalesTax
I am yet to study the book Pattern Hatching. However, i tried to accumulate all my knowledge on Design Pattern and solved a problem of Accountancy. i would like to share it with you. Let me, first of all, state the problem.
The Problem :
Basic sales tax is applicable at a rate of 10% on all goods, except books, food, and medical products that are exempt. Import duty is an additional sales tax applicable on all imported goods at a rate of 5%, with no exemptions. Also the Sales Tax should be rounded off to the nearest 0.05.
This being the problem, we need to come out with a solution for this problem.
Now let me tell you how my thought process went into it to think it at an abstract level.
First of all, i thought to make two top level classes. One that will define the Items having different benchmarks for Sales Tax and Import Duty; i.e.
- Food, Medical and Book items which are not imported and hence exempted from both sales tax and import duty
- Non Food Book and Medical items which are not imported and hence will have just the Sales Tax
- Food Book and Medical items which are imported and hence will have only import duty
- Non food book and medical items which are imported and hence will have both Sales Tax and Import Duty
And the other for the Tax Calculation algorithm for different items.
Then i thought this is a perfect match for Strategy Pattern that i had studied in the GoF book. I thought about that pattern keeping in mind for the future expansion of the Tax Calculation Algorithm. What i mean is that for the present problem, the calculation is simple. And hence it does not need any other Strategy. However, for the future purpose if the Tax Calculation Algorithm is changed to some complicated one, then we can just Subclass the Tax Calculation class and attach that strategy to the Item Class.
Next i thought, won't it be nice to get a Factory Class through which the client can create different Items on the fly. Hence i have decided to create an ItemCreator class which is nothing but a parameterized factory class for creating different Items on the fly.
And i came out with the following solution.
The Item class Hierarchy:
/*
* Item.h
*
* Created on: Jun 7, 2011
* Author: som
*/
#ifndef ITEM_H_
#define ITEM_H_
class SalesTax;
//This represents the Items which don't have an Import duty or any sales tax
class Item
{
public:
//Constructors
Item();
Item (SalesTax* aSalesTax);
//Interface Functions for Item
//To calculate the price after tax and import duty
virtual void CalculateTotalPrice();
//To calculate the total tax and import duty
virtual void CalculateTotalTax();
//To set the price of the Items
void SetPrice(double aPrice);
//To get the price of the Items before tax
double getPrice();
//To get the price of the items after tax
double getTotalPrice();
//To get the total tax and import duty of the items
double getTax();
//Data
protected:
//Works as the Strategy of the Sales Tax problem.
//If in future the tax calculation becomes more complicated for different Items
//we will just have to change this Strategy. We can also subclass this Strategy class
//for future expansion of the tax calculation strategy
SalesTax* iSalesTax;
//Data
protected:
//These are the basic properties of any Item.
//Hence these are made protected members so that the subclasses of Item can inherit
//these properties
double iPrice;
double iTotalPrice;
double iTotalTax;
};
//This class represents the Items which have only Import Duty
class ImportedItem : virtual public Item
{
public:
//Constructors
ImportedItem();
//This constructor helps to create Items having only Import duty
ImportedItem(SalesTax* aSalesTax, double aImportDuty);
//Override
virtual void CalculateTotalTax();
protected:
double iImportDuty;
};
//This class represents the Items which have only Sales Tax but no Import Duty
class NonFoodBookMedicalItem : virtual public Item
{
public:
//Constructors
NonFoodBookMedicalItem();
//This constructor helps to create Items having only Sales tax
NonFoodBookMedicalItem(SalesTax* aSalesTax, double aRate);
//Override
virtual void CalculateTotalTax();
protected:
double iRate;
};
//This class represents the Items which have got both Import Duty as well as sales Tax
class NormalItem: public ImportedItem, public NonFoodBookMedicalItem
{
public:
NormalItem();
//This constructor helps to create Items having both Sales tax and Import duty
NormalItem(SalesTax* aSalesTax, double aRate, double aImportDuty);
//Override
virtual void CalculateTotalTax();
};
#endif /* ITEM_H_ */
/*
* Item.cpp
*
* Created on: Jun 7, 2011
* Author: som
*/
#include "SalesTax.h"
#include "Item.h"
Item::Item(){}
Item::Item(SalesTax* aSalesTax):iSalesTax(aSalesTax),iPrice(0),iTotalPrice(0),iTotalTax(0)
{
}
void Item::CalculateTotalPrice()
{
iTotalPrice = iPrice + iTotalTax;
}
double Item::getTotalPrice()
{
return iTotalPrice;
}
void Item::CalculateTotalTax()
{
iTotalTax = iSalesTax->ComputeSalesTax(iPrice, 0, 0);
}
void Item::SetPrice(double aPrice)
{
iPrice = aPrice;
}
double Item::getPrice()
{
return iPrice;
}
double Item::getTax()
{
return iTotalTax;
}
ImportedItem::ImportedItem(){}
ImportedItem::ImportedItem(SalesTax* aSalesTax, double aImportDuty):Item(aSalesTax)
{
iImportDuty = aImportDuty;
}
void ImportedItem::CalculateTotalTax()
{
iTotalTax = iSalesTax->ComputeSalesTax(iPrice, 0, iImportDuty);
}
NonFoodBookMedicalItem::NonFoodBookMedicalItem(){}
NonFoodBookMedicalItem::NonFoodBookMedicalItem(SalesTax* aSalesTax, double aRate):Item(aSalesTax)
{
iRate = aRate;
}
void NonFoodBookMedicalItem::CalculateTotalTax()
{
iTotalTax = iSalesTax->ComputeSalesTax(iPrice, iRate, 0);
}
NormalItem::NormalItem() {}
NormalItem::NormalItem(SalesTax* aSalesTax, double aRate, double aImportDuty):Item(aSalesTax)
{
iRate = aRate;
iImportDuty = aImportDuty;
}
void NormalItem::CalculateTotalTax()
{
iTotalTax = iSalesTax->ComputeSalesTax(iPrice, iRate, iImportDuty);
}
/*
* ItemCreator.h
*
* Created on: Jun 7, 2011
* Author: som
*/
#ifndef ITEMCREATOR_H_
#define ITEMCREATOR_H_
#include "Item.h"
const int ITEM_WITH_NOSALESTAX_AND_IMPORTDUTY = 1;
const int ITEM_WITH_NOSALESTAX_ONLY_IMPORTDUTY = 2;
const int ITEM_WITH_ONLY_SALESTAX_AND_NOIMPORTDUTY = 3;
const int ITEM_WITH_BOTH_SALESTAX_AND_IMPORTDUTY = 4;
const double SALES_TAX_RATE = 10;
const double IMPORT_DUTY_RATE = 5;
class Not_A_Standard_Item_Type_Exception
{
public:
void printerrormsg();
};
class ItemCreator
{
public:
virtual Item* Create(int aItemId);
};
#endif /* ITEMCREATOR_H_ */
/*
* ItemCreator.cpp
*
* Created on: Jun 7, 2011
* Author: som
*/
#include "ItemCreator.h"
#include "Item.h"
#include "SalesTax.h"
#include <iostream>
using namespace std;
void Not_A_Standard_Item_Type_Exception::printerrormsg()
{
cout<<"Not the right Item Type..."<<endl;
}
Item* ItemCreator::Create(int aItemId)
{
SalesTax* st = new SalesTax();
switch(aItemId)
{
case ITEM_WITH_NOSALESTAX_AND_IMPORTDUTY:
return new Item(st);
break;
case ITEM_WITH_NOSALESTAX_ONLY_IMPORTDUTY:
return new ImportedItem(st,IMPORT_DUTY_RATE);
break;
case ITEM_WITH_ONLY_SALESTAX_AND_NOIMPORTDUTY:
return new NonFoodBookMedicalItem(st,SALES_TAX_RATE);
break;
case ITEM_WITH_BOTH_SALESTAX_AND_IMPORTDUTY:
return new NormalItem(st,SALES_TAX_RATE,IMPORT_DUTY_RATE);
break;
default:
throw Not_A_Standard_Item_Type_Exception();
}
}
/*
* SalesTax.h
*
* Created on: Jun 7, 2011
* Author: som
*/
#ifndef SALESTAX_H_
#define SALESTAX_H_
//This class works as the Strategy of the Sales tax problem
class SalesTax
{
public:
//Default constructor
SalesTax();
//This function helps to compute the Sales Tax
virtual double ComputeSalesTax(double aPrice, double aRate, double aImportduty);
private:
//This is an helper function which will round off the sales tax
double RoundOff(double aTax);
};
#endif /* SALESTAX_H_ */
/*
* SalesTax.cpp
*
* Created on: Jun 7, 2011
* Author: som
*/
#include "SalesTax.h"
SalesTax::SalesTax(){}
double SalesTax::ComputeSalesTax(double aPrice, double aRate, double aImportduty)
{
double tx = (aPrice*aRate/(double(100))) + (aPrice*aImportduty/(double(100)));
return RoundOff(tx);
}
//private:
double SalesTax::RoundOff(double aTax)
{
int taxTemp = (int)aTax;
double decimaltaxTemp = (double)(aTax - (int)taxTemp);
int tempy = (int)(1000*decimaltaxTemp)/100;
int tempz = (int)(1000*decimaltaxTemp - tempy*100);
int temp = (int)(tempz/10);
int t = tempz%10;
if (t >= 5)
temp+=1;
return (double)(taxTemp + tempy*(0.1) + temp*(0.01));
}
/*
* main.cpp
*
* Created on: Jun 7, 2011
* Author: som
*/
#include "SalesTax.h"
#include "Item.h"
#include "ItemCreator.h"
#include <iostream>
#include <vector>
using namespace std;
int main()
{
typedef vector<Item*> listOfItem;
listOfItem::iterator theIterator;
listOfItem Basket;
char answer = 'n';
double totalprice = 0;
double totaltax = 0;
do
{
int type_of_item;
cout<<"Enter the type of Item...1,2,3,4"<<endl;
cout<<"1 for ITEM_WITH_NOSALESTAX_AND_NOIMPORTDUTY"<<endl;
cout<<"2 for ITEM_WITH_NOSALESTAX_ONLY_IMPORTDUTY"<<endl;
cout<<"3 for ITEM_WITH_ONLY_SALESTAX_AND_NOIMPORTDUTY"<<endl;
cout<<"4 for ITEM_WITH_BOTH_SALESTAX_AND_IMPORTDUTY"<<endl;
cin>>type_of_item;
ItemCreator* itemCreator = new ItemCreator();
try
{
Item* item = itemCreator->Create(type_of_item);
cout<<"Enter the price of the Item"<<endl;
double price;
cin>>price;
item->SetPrice(price);
Basket.push_back(item);
}
catch(Not_A_Standard_Item_Type_Exception& e)
{
e.printerrormsg();
}
cout<<"Do you want to continue... Y/N"<<endl;
cin>>answer;
}
while (answer =='y');
theIterator = Basket.begin();
int pos = 0;
while (theIterator != Basket.end())
{
Basket.at(pos)->CalculateTotalTax();
totaltax+=Basket.at(pos)->getTax();
Basket.at(pos)->CalculateTotalPrice();
double price = Basket.at(pos)->getPrice();
double price_after_tax = Basket.at(pos)->getTotalPrice();
totalprice+=price_after_tax;
cout<<"Item"<<pos+1<<" price "<<price<<endl;
theIterator++;
pos++;
}
cout<<"------------"<<endl;
cout<<"Toal tax "<<totaltax<<endl;
cout<<"Total price "<<totalprice<<endl;
return 1;
}
Thus the problem is solved using two common design pattern concepts - Strategy Pattern and Parameterized Factory Pattern.
This is the way i am trying to move from the problem domain to the solution domain using design pattern concepts.
Hope this helps others who are studying Design Pattern.
Top comments (0)