简体   繁体   中英

Workaround for returning object in abstract class

I'm working on a payroll program for school and have a Payroll driver, Employee class, Hourly class (which extends Employee), Salaried class(extends Employee), and SalariedPlusCommission class (extends Salaried). The code below is the Employee object and the load() method from Employee (also a load() method in each subclass). I have to have an abstract method getEarnings() so the entire Employee class is abstract. I'm getting an error that says "Employee is abstract; cannot be instantiated". I understand why I'm getting the error but I don't know how to get the info into my Employee object.

    public Employee(String name, String socialSecurityNumber, int month, int week)
        {
            this.name=name;
            this.socialSecurityNumber=socialSecurityNumber;
            this.month=month;
            this.week=week;              
        }

        public static Employee load()
        {
            Scanner stdIn = new Scanner (System.in);
            System.out.println("Name ==> ");
            name=stdIn.nextLine();
            System.out.println("Social Security Number ==>");
            socialSecurityNumber=stdIn.nextLine();
            System.out.println("Birthday Month '('1-12')' ==> ");
            month=stdIn.nextInt();
            System.out.println("Birthday Bonus Week '('1-4')' ==>");
            week=stdIn.nextInt();
            return new Employee(name, socialSecurityNumber, month, week);
        }

If it helps here is the Hourly object and load() method from Hourly:

public Hourly(String name, String socialSecurityNumber, int month, int week, double hourlyPay, double hoursWorked)
{
    super(name, socialSecurityNumber, month, week);
    this.hourlyPay=hourlyPay;
    this.hoursWorked=hoursWorked;  
}

public static Hourly load()
{
    Scanner stdIn = new Scanner (System.in);
    System.out.println("Hourly Pay ==> ");
    hourlyPay=stdIn.nextDouble();
    System.out.println("Hours Worked This Past Week ==>");
    hoursWorked=stdIn.nextDouble();
    return new Hourly(name, socialSecurityNumber, month, week, hourlyPay, hoursWorked);
}

As soon as you add an abstract method to a class then you can no longer instantiate it. In your scheme, you can instantiate Hourly, Salaried, and SalariedPlusCommission if they provide an implementation for getEarnings() and any other abstract methods declared by Employee.

A common intent for a class hierarchy like this is to use Employee to hold behaviors (code) common to all your sub-classes. You extend it and never instantiate it directly.

If you do need to instantiate Employee, then you must provide an implementation of getEarnings() and probably ALSO override the implementation in each subclass. The base implementation can return a null or even throw an exception if you like. Having a NOOP base implementation strikes me as a potential "bad code smell", but I don't know what else you are trying to accomplish.

You could also create an IEarn interface with just that method and have each subclass implement it (but not Employee). The problem here is that you won't be able to declare all your entities as the base class for treating them polymorphically with regards to earning. You won't be able to do:

Employee foo = new Hourly();
Employee baz = new Salaried();
baz.getEarnings();
foo.getEarnings();

You'd have to do:

IEarn foo = new Hourly();
IEarn baz = new Salaried();
baz.getEarnings();
foo.getEarnings();

But the typical thing to do here would be to design your class hierarchy so that Employee was useful as an abstract class and never instantiated directly.

Employee is an abstract class, which means it does not implement all of its methods. It is up to subclasses to implement those methods with the proper behavior. Therefore, it does not make sense to load an Employee , while it does make sense to load an Hourly , since it implements all methods.

You shouldn't be trying to instantiate an employee. Instead, remove the load() method from the Employee class and keep only the Hourly , Salaried and SalariedPlusCommission load() methods.

If you need to create a load() method for Employee , then ask the user what kind of employee he/she wants:

System.out.println("Type (Hourly, Salaried or SalariedPlusCommission): ");
t=stdIn.nextLine();
switch(t) {
   case "Hourly":
       return Hourly.load()
       break;
    // other cases
}

Note, however, that this isn't good practice and the Employee class shouldn't be responsible for instantiating its subclasses. This requirement comes to the code that is using Employee . For instance, the Employee class should not be required to know about all of its subclass. This onus comes to the code that uses Employee , as only that code can know which employee subtypes it wants to support.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM