2
\$\begingroup\$

I had an assignment last semester to program a payroll app utilizing methods. I went back to it and re-wrote it to include an extra class as well. I would like some feedback regarding whether my code is following the Single Responsibility SOLID principle - should the class be split further into more classes?

I would also like some tips on how I could format the output nicer using printf as depending on how long the names or pay are, the columns get misaligned.

Here is the code:

//Java payroll program utilizing methods and classes

import java.util.Scanner;

 public class Payroll
{
   public static void main(String[]args)
   {  
      //declaration block
      Payroll app = new Payroll();   
      int SIZE;
      double overtimeEarnings = 0.0;
      double averageGross = 0.0;
      double totalGross = 0.0;
      
      //taxes and fees constants 
      final double fTax = 0.12;
      final double sTax = 0.06;
      final double uFees = 0.01;
  
      double sentinel = 0.0;
      
      Scanner kb = new Scanner(System.in);
      
      System.out.println("Welcome to the Payroll Calculator\n");
      
      do {
            System.out.println("How many employees?: ");
            SIZE = kb.nextInt();
            Employees dataHousing = new Employees(SIZE);

            
            dataHousing.input();
            dataHousing.calculateGross();
            dataHousing.calculateNet(sTax, fTax, uFees);
            
            
            totalGross = app.calculateTotalGross(dataHousing.grossPay, SIZE);
            averageGross = app.calculateAverageGross(totalGross, SIZE);
            app.output(dataHousing, totalGross, averageGross, SIZE);
            
            //clear after output in case user wants to repeat program
            totalGross = 0.0;
            averageGross = 0.0;
            
            System.out.println("\nPlease enter 1 to repeat the program, any other number to quit");
            sentinel = app.input();
            
            }
      while(sentinel == 1);
      
            System.out.println("Goodbye!");
   
   
   }
   double input()
   {
      Scanner kb = new Scanner(System.in);
      double value;
      value = Double.parseDouble(kb.nextLine());
      
      return value;
   }
   double calculateTotalGross( double gIncome[], final int SIZE)
   {
         double totalGross = 0.0;

         for(int i = 0; i < SIZE; i++)
         {  
            totalGross += gIncome[i];
                     
         }
   
         return totalGross;
   }
   
  double calculateAverageGross(double tGross, final int SIZE)
  {   
            
      return tGross/SIZE;
   
  }

  void output(Employees x,double tGross, double aGross, final int SIZE)
  {
         System.out.printf("%70s%n", "Data Housing Corp. Payroll");
         System.out.printf("%110s%n","__________________________________________________________________________________________________________________");
         System.out.printf("%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s%n", "First Name |" , "M Initial |" , "Surname |" , "Rate/h |" , "OT Hours |" , 
                                    "Gross $ |" , "State Tax |" , "Fed Tax |" , "Union fees |"  , "Net $ |");
                  
         for (int i = 0; i < SIZE; i++)
         {
            System.out.printf("%5s %8s %15s %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f %10.2f%n%n",x.firstName[i] , x.MI[i] , x.lastName[i] , 
            x.payRate[i] , x.overtimeHours[i] , x.grossPay[i], x.stateTax[i] , + x.fedTax[i] , x.unionFees[i] , x.netPay[i]);

         }
                    
          System.out.printf("Total Gross is: %.2f%n" , tGross);
          System.out.printf("Average Gross is: %.2f%n" , aGross);
          
  }
}
class Employees
{
   String[] firstName;
   String[] lastName;
   char[] MI;
   double[] hours;
   double[] overtimeHours;
   double[] payRate;
   double[] grossPay;
   double[] netPay;
   double[] stateTax;
   double[] fedTax;
   double[] unionFees;
   
   final int SIZE;
   
   Employees(int SIZE)
   {  
      this.SIZE = SIZE;
      this.firstName = new String[SIZE];
      this.lastName = new String[SIZE];
      this.MI = new char[SIZE];
      this.hours = new double[SIZE];
      this.payRate = new double[SIZE];
      this.grossPay = new double[SIZE];
      this.overtimeHours = new double[SIZE];
      this.netPay = new double[SIZE];
      this.stateTax = new double[SIZE];
      this.fedTax = new double[SIZE];
      this.unionFees = new double[SIZE];
   }
  
   void input()
   {
      for(int i = 0; i < SIZE; i++)
      {
         System.out.println("Please enter the First Name: ");
         firstName[i] = keyboard();
                                   
         System.out.println("Please enter the Middle Initial: ");
         MI[i] = keyboard().charAt(0);
                           
         System.out.println("Please enter the Last Name: ");
         lastName[i] = keyboard();
               
         System.out.println("Please enter the hours worked: ");
         hours[i] = Double.parseDouble(keyboard());
            
         System.out.println("Please enter the hourly pay rate: ");
         payRate[i] = Double.parseDouble(keyboard());
       } 
   }
      
   String keyboard()
   {
      Scanner kb = new Scanner(System.in);
      String value;
      value = kb.nextLine();
      
      return value;
   }
/**  
*  gross method calculates the gross income of each employee and stores the value in grossPay member
*
*  
*/    
   void calculateGross()
   {  
      double overtimeEarnings;
      for(int i = 0; i < SIZE; i++)
      {
         if(hours[i] > 40) 
         {
            overtimeHours[i] = hours[i] - 40;
            overtimeEarnings = overtimeHours[i] * (payRate[i] * 1.5);
            grossPay[i] = ((hours[i] - overtimeHours[i]) * payRate[i]) + overtimeEarnings;
            
         }else {
                  overtimeHours[i] = 0.0;
                  grossPay[i] = hours[i] * payRate[i];
               }
       }
       
    }
/**  
*  Calculate Net method calculates the net pay  of each employee after taxes and stores it in netPay member
*
*  @param sT = stateTax
*  @param fT = fedTax
*  @param uF = unionFees
*/ 

    void calculateNet(final double sT,final double fT, final double uF)
    {     

      for(int i = 0; i < SIZE; i++)
      {
         stateTax[i] = grossPay[i] * sT;
         fedTax[i] = grossPay[i] * fT;
         unionFees[i] = grossPay[i] * uF;
         netPay[i] = grossPay[i] - (stateTax[i] + fedTax[i] + unionFees[i]);
      
      }
    }


}

```
\$\endgroup\$
  • \$\begingroup\$ bump :((((((((( \$\endgroup\$ – shaggy Jun 16 '20 at 10:49
  • 1
    \$\begingroup\$ Give us time to answer. Reviewing a code and writing a polite, well described and useful answer take time. \$\endgroup\$ – gervais.b Jun 16 '20 at 11:48
  • \$\begingroup\$ @gervais.b didn't mean to rush! I'm new to the forum and wasn't sure if anyone would answer after so many hours. \$\endgroup\$ – shaggy Jun 16 '20 at 12:50
2
\$\begingroup\$

So, you would like to know if your code is "following the Single Responsibility SOLID principle". S.O.L.I.D. stand for Single responsibility, Open-closed principle, Liskov substitution principle, Interface segregation and Dependency Inversion.

Single responsibility

One class have a single responsibility. But both Payroll and Employees are mixing business logic, IOs and datas.

Open-closed principle

Classes should be open for extension but closed for modification. This is not easily applicable in your case.

Try to implement different way to compute the payroll.

Liskov substitution

Classes should be replaceable with subtypes. This one is not applicable because there are no inheritance in your code.

Interface segregation

Client should not depend on interfaces they don't use. Like for the previous, this one is not easily applicable in a small system.

Dependency Inversion

Depend on abstraction. Once again, this is not easily applicable in a small system. But one way will be to pass your Employees to Payroll instead of creating the instance. By doing that you can easily imagine to have another implementation of your Employess.


You also want some tips on formatting but you are already using printf. However your column are still missaligned due to different name length.

One solution would be to compute the minimum length of your columns to build the formatting pattern.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.