Problem Statement
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.
When I purchase items I receive a receipt which lists the name of all the items and their price (including tax), finishing with the total cost of the items, and the total amounts of sales taxes paid. The rounding rules for sales tax are that for a tax rate of n%, a shelf price of p contains (np/100 rounded up to the nearest 0.05) amount of sales tax.
- 1 book at 12.49
- 1 music CD at 14.99
- 1 chocolate bar at 0.85
Discussion
- Sales Tax is a kind of Sales Tax
- Import duty is also kind of Sales Tax
- Sales Tax has a rate which is a Decimal
- Books are a kind of item
- Food is a kind of item
- Medicines are a kind of item.
- Items may be imported
- Sales Tax will have some policy which will define that whether sales tax is applicable or not on a given item.
- An item has Sales Price in the form of Decimal.
- A Receipt containing list of items, price and their taxes
- Total Price
- Total Tax
- Item - It will be an abstract class and Book will inherit from it.
- SalesTax - It will be an abstract class and BasicSalesTax class will inherit from it.
- A Store will have different kinds of product.
- User can put item in cart and purchase it.
- Payment counter will calculate Sales Tax as per eligibility of item and price. It will also calculate total price. It will generate bill by containing all details.
Design Pattern Approach
- Abstract Factory - ProductFactory
- Concrete Factory - BookProductFactory, FoodProductFactory, MedicineProductFactory
- Abstract Product - Product
- Concrete Product - BookProduct, FoodProduct, MedicineProduct
- Client - StoreShelf
- If new Product will be added, then there will be no need to change the existing client code.
- Strategy - ITaxCalculator
- Concrete Strategy - LocalTaxCalculator
- Context - Biller
- We can add new algorithm for Tax Calculation in the feature easily and algorithm can be selected at run time.
- The actual creation of a TaxCalculator will be delegated to Factory method.
Sequence Diagram of Sales Tax Problem

Implementation
I will add a short code example. For more details find the attached code.
A Short code of Abstract Factory,
- using SalesTax.ProductFactories;
- using System;
- namespace SalesTax.Products
- {
- public abstract class Product
- {
- protected string Name { get; set; }
- private double _price;
- public double Price
- {
- set { _price = value; }
- get { return _price * Quantity; }
- }
- public bool Imported { get; set; }
- public int Quantity { get; set; }
- public double TaxedCost { get; set; }
- public Product()
- {
- this.Name = string.Empty;
- this.Price = 0.0;
- this.Imported = false;
- this.Quantity = 0;
- this.TaxedCost = 0.0;
- }
- public Product(String name, double price, bool imported, int quantity)
- {
- this.Name = name;
- this.Price = price;
- this.Imported = imported;
- this.Quantity = quantity;
- }
- public override string ToString()
- {
- return (Quantity + " " + ImportedToString(Imported) + " " + Name + " : " + TaxedCost);
- }
- public String ImportedToString(bool imported)
- {
- if (!imported)
- return string.Empty;
- else
- return "imported";
- }
- public abstract ProductFactory GetFactory();
- public abstract double GetTaxValue(String country);
- }
- }
- using SalesTax.ProductFactories;
- using SalesTax.TaxCalculations;
- using System;
- namespace SalesTax.Products
- {
- public class BookProduct : Product
- {
- public BookProduct()
- : base()
- {
- }
- public BookProduct(String name, double price, bool imported, int quantity)
- : base(name, price, imported, quantity)
- {
- }
- public override ProductFactory GetFactory()
- {
- return new BookProductFactory();
- }
- public override double GetTaxValue(string country)
- {
- if (country == "Local")
- return LocalTaxValues.BOOK_TAX;
- else
- return 0;
- }
- }
- }
- using SalesTax.Products;
- using System;
- namespace SalesTax.ProductFactories
- {
- public abstract class ProductFactory
- {
- public abstract Product CeateProduct(String name, double price, bool imported, int quantity);
- }
- }
- using System;
- using System.Collections.Generic;
- namespace SalesTax.ProductFactories
- {
- public class BookProductFactory : ProductFactory
- {
- public override Products.Product CeateProduct(string name, double price, bool imported, int quantity)
- {
- return new Products.BookProduct(name, price, imported, quantity);
- }
- }
- }
- using System;
- namespace SalesTax.TaxCalculations
- {
- double CalculateTax(double price, double tax, bool imported);
- }
- }
- using SalesTax.utils;
- using System;
- namespace SalesTax.TaxCalculations
- {
- /// <summary>
- /// It Calculates Total Tax Cost According to Local Region Specification.
- /// </summary>
- public class LocalTaxCalculator : ITaxCalculator
- {
- public double CalculateTax(double price, double localTax, bool imported)
- {
- double tax = price * localTax;
- if (imported)
- tax += (price * 0.5);
- //rounds off to nearest 0.05;
- tax = TaxUtil.RoundOff(tax);
- return tax;
- }
- }
- }
- using System;
- namespace SalesTax.TaxCalculations
- {
- public class TaxCalculatorFactory
- {
- private Dictionary<String, ITaxCalculator> taxCalculators;
- public TaxCalculatorFactory()
- {
- taxCalculators = new Dictionary<String, ITaxCalculator>();
- RegisterInFactory("Local", new LocalTaxCalculator());
- }
- public void RegisterInFactory(string strategy, ITaxCalculator taxCalc)
- {
- taxCalculators.Add(strategy, taxCalc);
- }
- public ITaxCalculator GetTaxCalculator(String strategy)
- {
- ITaxCalculator taxCalc = (ITaxCalculator)taxCalculators[strategy];
- return taxCalc;
- }
- public int GetFactorySize()
- {
- return taxCalculators.Count;
- }
- }
- }
siddhartha sharnaPosted May 8, 2018, 2:54 AM
Hi, I have a quick question here Why we use the abstract class in stead of interfaces for Basic sale Tax.
Prasanna MuraliPosted Oct 9, 2016, 10:10 AM
Nice post..
SubashPosted Oct 8, 2016, 5:57 AM
nice explain