Facade Pattern with an Implementation

Facade pattern is one of the most frequently used Structural design pattern. GoF defined this pattern as:

Provide a unified interface to a set of interfaces in a subsystem. Facade Pattern defines a higher-level interface that makes the subsystem easier to use.

beep beep.. Msg received… salary credited to ur a/c”

Without any 2nd thought we can accept: This is one of the most important sms, we are waiting for the whole month.

But have you ever been consider how complex is your salary calculation process. This process may expose lot of interfaces to interact with it. To complete a process flow we may have to interact with multiple interfaces.

Salary calculation process may include

  • Calculate your basic pay
  • Calculate HRA
  • Calculate Other/Special allowances
  • Calculate LTA
  • Calculate Medical Reimbursement
  • Calculate Bonus
  • Calculate Tax
  • Calculate Professional Tax
  • Calculate Provident Fund

It has many more components, but for the sake of simplicity we are considering these components only.

Let us represent this flow by a diagram:

salary_complex

To simplify this interaction process, we introduce facade layer. Facade exposes a simplified interface for the underlying subsystem. It hides the complexities of the sub-system and provides an interface to the client from where the client can access the system. It can be taken as one level of abstraction over an existing layer.

Let us simplify the salary calculation process by introducing a facade layer. If we divide our salary components into different categories then we can have:

Earning Components: Basic, HRA, Other/Special Allow. , Medical, bonus etc.

Deduction Components: Tax, Professional Tax, Provident Fund etc.

So we can have a simplified interface exposed to client that calculates the earning components and deduction components. Internally it interact with the underlying sub-system to get the job done.So after introducing the Facade layer lets redraw the diagram:

simple_salary

Implementation:

First we will create the complex sub-system with calculation logic. Here we have 2 interfaces and their concrete implementation to calculate all the earning and deduction components.

IEarningPayComponent.java

public interface IEarningPayComponent {

  public String getBasicPay(String empId)throws Exception;

  public String getHRA(String empId)throws Exception;

  public String getOtherAllowances(String empId)throws Exception;

  public String getMedicalReimbursement(String empId)throws Exception;

  public String getLTA(String empId)throws Exception;
}

And now implement this interface to provide concrete calculation logic.

EarningPayComponentImpl.java

package com.design.facade;

public class EarningPayComponentImpl implements IEarningPayComponent {

  @Override
  public String getBasicPay(String empId) throws Exception {
    /**
     * Basic pay calculation logic for Employee
     *
     */
    return "Basic pay for employee.\n";
  }

  @Override
  public String getHRA(String empId) throws Exception {
    String city = getCityOfEmployee(empId);
    /**
     * HRA calculation logic for Employee HRA depends upon city
     */

    return "HRA for employee.\n";
  }

  private String getCityOfEmployee(String empId) {
    return "city";
  }

  @Override
  public String getOtherAllowances(String empId) throws Exception
  {
    return "Other Allowances pay for employee.\n";
  }

  @Override
  public String getMedicalReimbursement(String empId) throws Exception
  {
    return "Medical Reimbursement pay for employee.\n";
  }

  @Override
  public String getLTA(String empId) throws Exception
  {
    return "LTA for employee.\n";
  }
}

Similarly we have an interface and implementation for deduction component

IDeductionPayComponent.java

package com.design.facade;

public interface IDeductionPayComponent {

  public String getTaxAmountToDeduct(String empId) throws Exception;

  public String getPTaxAmountToDeduct(String empId) throws Exception;

  public String getPFAmountToDeduct(String empId) throws Exception;
}

DeductionPayComponentImpl.java

package com.design.facade;

public class DeductionPayComponentImpl implements IDeductionPayComponent {

  @Override
  public String getTaxAmountToDeduct(String empId) throws Exception {
    /**
     * Tax calculation logic here. Who ever worked in some
     * payroll software knows about these complexities.
     */
    return "Tax amount should be deducted.\n";
  }

  @Override
  public String getPTaxAmountToDeduct(String empId) throws Exception
 {
    return "PTax amount should be deducted.\n";
 }

  @Override
  public String getPFAmountToDeduct(String empId) throws Exception
  {
    return "PF amount [Employee contribution] should be deducted.\n";
  }
}

Now we will introduce facade layer, which is actually a simple interface to calculate the salary. It has 2 methods exposed for calculate earnings and deduction components. Internally it will communicate with IEarningPayComponent and IDeductionPayComponent to get the job done.

PayFacade.java

package com.design.facade;

public interface PayFacade {

  // simple interface exposed to clinet
  public String calculateEarningComponents(String empId) throws Exception;

  public String calculateDeductionComponents(String empId) throws Exception;
}

PayFacadeImpl.java

package com.design.facade;

public class PayFacadeImpl implements PayFacade {

  private IEarningPayComponent iEarningPayComponent;
  private IDeductionPayComponent iDeductionPayComponent;

  public PayFacadeImpl()
  {
    this.iEarningPayComponent = new EarningPayComponentImpl();
    this.iDeductionPayComponent = new DeductionPayComponentImpl();
  }

  @Override
  public String calculateEarningComponents(String empId) throws Exception
  {
    String totalEarning = iEarningPayComponent.getBasicPay(empId);
    totalEarning += iEarningPayComponent.getHRA(empId);
    totalEarning += iEarningPayComponent.getOtherAllowances(empId);
    totalEarning += iEarningPayComponent.getLTA(empId);
    totalEarning += iEarningPayComponent.getMedicalReimbursement(empId);
    return totalEarning;
  }

  @Override
  public String calculateDeductionComponents(String empId) throws Exception
  {
    String totalDeduction = iDeductionPayComponent.getTaxAmountToDeduct(empId);
    totalDeduction += iDeductionPayComponent.getPTaxAmountToDeduct(empId);
    totalDeduction += iDeductionPayComponent.getPFAmountToDeduct(empId);
    return totalDeduction;
  }

}

Now test this ::

public class Test {

    public static void main(String[] args) throws Exception {

        String empId = "I_AM";
        PayFacade payFacade = new PayFacadeImpl();
        System.out.println("======= PaySlip ========= ");
        System.out.println("Earning Components:: ");
        System.out.println("--------------------");
        System.out.println(payFacade.calculateEarningComponents(empId));
        System.out.println("/////////////////////////// ");
        System.out.println("Deduction Components:: ");
        System.out.println("----------------------");
        System.out.println(payFacade.calculateDeductionComponents(empId));

    }
}

The O/P is :::

======= PaySlip =========
Earning Components::
--------------------
Basic pay for employee.
HRA for employee.
Other Allowances pay for employee.
LTA for employee.
Medical Reimbursement pay for employee.

///////////////////////////
Deduction Components::
----------------------
Tax amount should be deducted.
PTax amount should be deducted.
PF amount [Employee contribution] should be deducted.
 

 

CORE JAVA STRUCTURAL-PATTERNS