Monday, September 16, 2013

Singleton Design Pattern


Singleton Design Pattern

There are some instances in the application where we have to use just one instance of a particular class.

Singleton pattern is one of the simplest design patterns in Java, which comes under creational pattern.

Important :
* Ensure unique instance by defining class final to prevent cloning.
* May be extensible by the subclass by defining subclass final.
* Make a method or a variable public or/and static.
* Access to the instance by the way you provided.
* Well control the instantiation of a class.
* Define one value shared by all instances by making it static.



Example :

1. DisplayCurrencyFormat.java

package DesignPatterns.Singleton;

import java.text.DecimalFormat;

public class DisplayCurrencyFormat {

     private static DisplayCurrencyFormat currencyFormatuniqueInstance;

     private boolean ENABLE_ROUNDING = false;
     private boolean ENABLE_DECIMAL = false;
     private boolean ENABLE_GROUPING = false;
     private String ROUNDING_TYPE = "abs";

     public static synchronized DisplayCurrencyFormat getInstance(){

           if(null == currencyFormatuniqueInstance){
                 return currencyFormatuniqueInstance = new DisplayCurrencyFormat();
           }
           return null;
    }

    public String setDisplayFormat(double value){

           if(currencyFormatuniqueInstance.isENABLE_ROUNDING()){

                 if("ceil".equalsIgnoreCase(currencyFormatuniqueInstance.
getROUNDING_TYPE())){
                        value = Math.ceil(value);
                 }
                 if("floor".equalsIgnoreCase(currencyFormatuniqueInstance.
getROUNDING_TYPE())){
                       value = Math.floor(value);
                 }
                 if("abs".equalsIgnoreCase(currencyFormatuniqueInstance.
getROUNDING_TYPE())){
                       value = Math.abs(value);
                }
          }

          String retValue;
          if(currencyFormatuniqueInstance.isENABLE_DECIMAL() && currencyFormatuniqueInstance.isENABLE_GROUPING()){
                 DecimalFormat df1 = new DecimalFormat( "#,###,###,##0.00" );
                 retValue = df1.format(value);
          }else{
                 if(currencyFormatuniqueInstance.isENABLE_DECIMAL()){
                        DecimalFormat df2 = new DecimalFormat( "#####0.00" );
                        retValue = df2.format(value);
                }else
                if(currencyFormatuniqueInstance.isENABLE_GROUPING()){
                        DecimalFormat df3 = new DecimalFormat( "#,###,###,##0" );
                        retValue = df3.format(value);
                }else{
                        retValue = String.valueOf(value);
                }
         }
         System.out.println("value | retValue --> " + value + " | " + retValue);
         return retValue;
   }

   public boolean isENABLE_ROUNDING() {
         return ENABLE_ROUNDING;
   }

   public void setENABLE_ROUNDING(boolean eNABLE_ROUNDING) {
         ENABLE_ROUNDING = eNABLE_ROUNDING;
   }

   public boolean isENABLE_DECIMAL() {
         return ENABLE_DECIMAL;
   }

   public void setENABLE_DECIMAL(boolean eNABLE_DECIMAL) {
         ENABLE_DECIMAL = eNABLE_DECIMAL;
   }

   public boolean isENABLE_GROUPING() {
         return ENABLE_GROUPING;
   }

   public void setENABLE_GROUPING(boolean eNABLE_GROUPING) {
          ENABLE_GROUPING = eNABLE_GROUPING;
   }

   public String getROUNDING_TYPE() {
          return ROUNDING_TYPE;
   }

   public void setROUNDING_TYPE(String rOUNDING_TYPE) {
          ROUNDING_TYPE = rOUNDING_TYPE;
   }
}


2. SingletonDemo.java

package DesignPatterns.Singleton;

public class SingletonDemo {

      /**
      * @param args
      */
      public static void main(String[] args) {
              SingletonDemo demo = new SingletonDemo();
              demo.execute();
      }

      private void execute(){

              DisplayCurrencyFormat currencyFormatObj = DisplayCurrencyFormat.getInstance();
              currencyFormatObj.setENABLE_ROUNDING(true);
              currencyFormatObj.setENABLE_DECIMAL(true);
              currencyFormatObj.setENABLE_GROUPING(true);
              currencyFormatObj.setROUNDING_TYPE("abs");
              currencyFormatObj.setDisplayFormat(10189.4);
      }
}


Output :

value | retValue [R-t|D-t|G-t]--> 10189.4 | 10,189.40
value | retValue [R-t|D-t|G-f]--> 10189.4 | 10189.40
value | retValue [R-t|D-f|G-t]--> 10189.4 | 10,189
value | retValue [R-t|D-f|G-f]--> 10189.4 | 10189.4
value | retValue [R-f|D-t|G-t]--> 10189.4 | 10,189.40
value | retValue [R-f|D-t|G-f]--> 10189.4 | 10189.40
value | retValue [R-f|D-f|G-t]--> 10189.4 | 10,189
value | retValue [R-f|D-f|G-f]--> 1189.4 | 10189.4

Factory Design Pattern

Factory Design Pattern

Factory design pattern comes under creational pattern as this pattern provides one of the best ways to create an object.
In Factory pattern, we create object without exposing the creation logic to the client and refer to newly created object using a common interface.

Important points -
* Connect parallel class hierarchies.
* A class wants its subclasses to specify the object.
* A class cannot anticipate its subclasses, which must be created.
* A family of objects needs to be separated by using shared interface.
* The code needs to deal with interface, not implemented classes.
* Hide concrete classes from the client.
* Factory methods can be parameterized.
* The returned object may be either abstract or concrete object.
* Providing hooks for subclasses is more flexible than creating objects directly.

Implementation - Example
We're going to create a EmployeeSalaryCalc interface and concrete classes implementing the EmployeeSalaryCalc interface. A factory class EmployeeSalaryCalcFactory is defined as a next step.

ExecuteEmployeeSalaryCalc, our executable class will use EmployeeSalaryCalcFactory to get a EmployeeSalaryCalc object. It will pass information (MANAGER / ENGINEER / SUPPORTSTAFF) to EmployeeSalaryCalcFactory to get the type of object it needs.






Step 1 – Create Interface : EmployeeSalaryCalc.java

package DesignPatterns.Factory;

public interface EmployeeSalaryCalc {

String getEmployeeName(int empID);
double overtimeCalculation(double basicSalary, int totHours);
double incentiveCalculation(double basicSalary, double target);
double incrementCalculation(double basicSalary, double assement);
double bonusCalculation(double basicSalary, boolean bonusApplicable);
double monthlySalarycalculation(double basicSalary, double overtime, double incentive, double increment, double bonus);

}


Step 2 – Create concrete class implementing the same interface.

2.1) ManagerSalaryCalculation.java

package DesignPatterns.Factory;

public class ManagerSalaryCalculation implements EmployeeSalaryCalc{

private String empName;
private int STD_HOURS = 160;
private double STD_INCENTIVE_RATES = 7.5;
private double STD_INCREMENT_PER = 7.5;
private double STD_BONUS_PER = 75;

    @Override
    public String getEmployeeName(int empID) {

         if(empID == 100){
              empName = "Sanjeeva Pathirana";
         }
         return empName;
    }

     @Override
     public double overtimeCalculation(double basicSalary, int totHours) {
          double otPerHour = 120;
          return otPerHour * (totHours - STD_HOURS);
     }

     @Override
     public double incentiveCalculation(double basicSalary, double target) {

           double incentive = 0D;
           if((Math.floor(target)>90) && (Math.floor(target)<=95)){
                  incentive = (STD_INCENTIVE_RATES * basicSalary * 0.75)/100;
           }
           if(Math.floor(target)>95){
                  incentive = (STD_INCENTIVE_RATES * basicSalary)/100;
           }
           return incentive;
     }

     @Override
      public double incrementCalculation(double basicSalary, double assement) {

           double increment = 0D;
           if((Math.floor(assement)>90) && (Math.floor(assement)<=95)){
                 increment = (STD_INCREMENT_PER * basicSalary * 3)/100;
           }
           if(Math.floor(assement)>95){
                 increment = (STD_INCREMENT_PER * basicSalary * 5)/100;
           }
           return increment;
     }

     @Override
     public double bonusCalculation(double basicSalary, boolean bonusApplicable) {

           double bonus = 0D;
           if(bonusApplicable){
                 bonus = basicSalary * ( STD_BONUS_PER / 100 );
           }
           return bonus;
     }

     @Override
     public double monthlySalarycalculation(double basicSalary, double overtime,
double incentive, double increment, double bonus) {

            return basicSalary + overtime + incentive + increment + bonus;
     }
}

2.2) EngineerSalaryCalculation.java

package DesignPatterns.Factory;

public class EngineerSalaryCalculation implements EmployeeSalaryCalc {
private String empName;
private int STD_HOURS = 180;
private double STD_INCENTIVE_RATES = 6.0;
private double STD_INCREMENT_PER = 5.0;
private double STD_BONUS_PER = 65;

     @Override
     public String getEmployeeName(int empID) {

           if(empID == 101){
                 empName = "Sandamali Silva";
           }
           return empName;
     }

     @Override
     public double overtimeCalculation(double basicSalary, int totHours) {
            double otPerHour = 100;
            return otPerHour * (totHours - STD_HOURS);
     }

     @Override
     public double incentiveCalculation(double basicSalary, double target) {

            double incentive = 0D;
            if((Math.floor(target)>90) && (Math.floor(target)<=95)){
                   incentive = (STD_INCENTIVE_RATES * basicSalary * 0.75)/100;
            }
            if(Math.floor(target)>95){
                   incentive = (STD_INCENTIVE_RATES * basicSalary)/100;
            }
            return incentive;
     }

     @Override
     public double incrementCalculation(double basicSalary, double assement) {

            double increment = 0D;
            if((Math.floor(assement)>90) && (Math.floor(assement)<=95)){
                   increment = (STD_INCREMENT_PER * basicSalary * 3)/100;
            }
            if(Math.floor(assement)>95){
                   increment = (STD_INCREMENT_PER * basicSalary * 5)/100;
            }
            return increment;
     }

     @Override
     public double bonusCalculation(double basicSalary, boolean bonusApplicable) {

            double bonus = 0D;
            if(bonusApplicable){
                  bonus = basicSalary * ( STD_BONUS_PER / 100 );
            }
            return bonus;
     }

     @Override
     public double monthlySalarycalculation(double basicSalary, double overtime,
double incentive, double increment, double bonus) {
            return basicSalary + overtime + incentive + increment + bonus;
     }
}

2.3) SupportStaffSalaryCalculation.java

package DesignPatterns.Factory;

public class SupportStaffSalaryCalculation implements EmployeeSalaryCalc {
private String empName;
private int STD_HOURS = 200;
private double STD_INCENTIVE_RATES = 5.0;
private double STD_INCREMENT_PER = 4.5;
private double STD_BONUS_PER = 60;

       @Override
       public String getEmployeeName(int empID) {

               if(empID == 102){
                      empName = "Mahinda Perera";
               }
               return empName;
       }

       @Override
       public double overtimeCalculation(double basicSalary, int totHours) {
              double otPerHour = 80;
              return otPerHour * (totHours - STD_HOURS);
       }

       @Override
       public double incentiveCalculation(double basicSalary, double target) {

              double incentive = 0D;
              if((Math.floor(target)>90) && (Math.floor(target)<=95)){
                    incentive = (STD_INCENTIVE_RATES * basicSalary * 0.75)/100;
              }
              if(Math.floor(target)>95){
                    incentive = (STD_INCENTIVE_RATES * basicSalary)/100;
              }
              return incentive;
       }

       @Override
       public double incrementCalculation(double basicSalary, double assement) {

              double increment = 0D;
              if((Math.floor(assement)>90) && (Math.floor(assement)<=95)){
                    increment = (STD_INCREMENT_PER * basicSalary * 3)/100;
              }
              if(Math.floor(assement)>95){
                    increment = (STD_INCREMENT_PER * basicSalary * 5)/100;
              }
              return increment;
       }

       @Override
       public double bonusCalculation(double basicSalary, boolean bonusApplicable) {

              double bonus = 0D;
              if(bonusApplicable){
                     bonus = basicSalary * ( STD_BONUS_PER / 100 );
              }
              return bonus;
       }

       @Override
       public double monthlySalarycalculation(double basicSalary, double overtime,
double incentive, double increment, double bonus) {
               return basicSalary + overtime + incentive + increment + bonus;
       }
}

Step 3 – Create a Factory to generate object of concrete class based on given information

package DesignPatterns.Factory;

public class EmployeeSalaryCalcFactory {

       //used to get object of type EmployeeSalaryCalc
       public EmployeeSalaryCalc getEmployeeSalaryCalc(String employee){

             if(null == employee){
                    return null;
             }else{
                    if("MANAGER".equalsIgnoreCase(employee)){
                           return new ManagerSalaryCalculation();
                    }
                    if("ENGINEER".equalsIgnoreCase(employee)){
                           return new EngineerSalaryCalculation();
                    }
                    if("SUPPORTSTAFF".equalsIgnoreCase(employee)){
                           return new SupportStaffSalaryCalculation();
                    }
             }
             return null;
       }
}

Step 4 - Use the Factory to get object of concrete class by passing an information.

package DesignPatterns.Factory;

public class ExecuteEmployeeSalaryCalc {

      /**
      * @param args
      */
      public static void main(String[] args) {

            ExecuteEmployeeSalaryCalc employeeSalaryCalc = new ExecuteEmployeeSalaryCalc();
            employeeSalaryCalc.doExecute();
      }

     private void doExecute(){

            EmployeeSalaryCalcFactory salaryCalc = new EmployeeSalaryCalcFactory();

            EmployeeSalaryCalc managerSalaryCalc = salaryCalc.getEmployeeSalaryCalc("MANAGER");
            printSalarySheet(managerSalaryCalc, 100, 100000, 180, 93.5, 91.75, false);

            EmployeeSalaryCalc engineerSalaryCalc = salaryCalc.getEmployeeSalaryCalc("ENGINEER");
            printSalarySheet(engineerSalaryCalc, 101, 80000, 185, 96.5, 95.75, false);

            EmployeeSalaryCalc suppStaffSalaryCalc = salaryCalc.getEmployeeSalaryCalc("SUPPORTSTAFF");
            printSalarySheet(suppStaffSalaryCalc, 102, 20000, 225, 98.5, 94.75, true);
     }

     private void printSalarySheet(EmployeeSalaryCalc employeeSalaryCalc, int empID, double basicSalary, int totHours, double target, double assement, boolean bonusApplicable){

            String empName = employeeSalaryCalc.getEmployeeName(empID);
            double overtime = employeeSalaryCalc.overtimeCalculation(basicSalary, totHours);
            double incentive = employeeSalaryCalc.incentiveCalculation(basicSalary, target);
            double increment = employeeSalaryCalc.incrementCalculation(basicSalary, assement);
            double bonus = employeeSalaryCalc.bonusCalculation(basicSalary, bonusApplicable);
            double monthlySalary= employeeSalaryCalc.monthlySalarycalculation(basicSalary, overtime, incentive, increment, bonus);

            System.out.println("============================");
            System.out.println("Employee ID : " + empID);
            System.out.println("Employee Name : " + empName);
            System.out.println("----------------------------");
            System.out.println("Basic : " + basicSalary);
            System.out.println("Overtime : " + overtime);
            System.out.println("Incentive : " + incentive);
            System.out.println("Increment : " + increment);
            System.out.println("bonus : " + bonus);
            System.out.println("Total : " + monthlySalary);
            System.out.println("----------------------------");
     }
}


Output
============================
Employee ID : 100
Employee Name : Sanjeeva Pathirana
----------------------------
Basic : 100000.0
Overtime : 2400.0
Incentive : 5625.0
Increment : 22500.0
bonus : 0.0
Total : 130525.0
----------------------------
============================
Employee ID : 101
Employee Name : Sandamali Silva
----------------------------
Basic : 80000.0
Overtime : 500.0
Incentive : 4800.0
Increment : 12000.0
bonus : 0.0
Total : 97300.0
----------------------------
============================
Employee ID : 102
Employee Name : Mahinda Perera
----------------------------
Basic : 20000.0
Overtime : 2000.0
Incentive : 1000.0
Increment : 2700.0
bonus : 12000.0
Total : 37700.0
----------------------------