接口代表了一种设计规范,同继承、多态一样,也是一种很重要的面向对象编程思想。
程序功能:
本程序在多态处理不同类型员工的工资的基础上,让基类Employee实现Payable接口,从而可以将员工工资的处理操作与应付款(如,采购款的支付)操作进行合并。从而,在更高层次实现系统的重用性。
类图如下,其中,除SalariedEmpolyee外,HourlyEmployee, ComissionEmployee也继承了Employee类。另外,BasePlusComissionEmployee继承ComissionEmployee。
测试结果:
Invoices and Employees processed polymorphically:
invoice: part number: 01234 (seat) quantity: 2 price per item: $375.00 payment due: $750.00
invoice: part number: 56789 (tire) quantity: 4 price per item: $79.95 payment due: $319.80
salaried employee: John Smith social security number: 111-11-1111 weekly salary: $800.00 payment due: $800.00
hourly employee: Lisa Barnes social security number: 888-88-8888 hourly wage: $40.00; hours worked: 50.00 payment due: $2,200.00
commission employee: Andrew Brown social security number: 999-99-9999 gross sales: $100,000.00; commission rate: 0.08 payment due: $8,000.00
base-salaried commission employee: Andy Jobs social security number: 666-66-6666 gross sales: $100,000.00; commission rate: 0.08; base salary: $600.00 payment due: $8,600.00 new base salary with 10% increase is: $660.00 |
测试代码:
1. 测试类
//Java How to Program, Exercise 10.15: Accounts Payable System Modification
//by pandenghuang@163.com
/**
* 10.15 (Accounts Payable System Modification) In this exercise, we modify the
* accounts payable application of Figs. 10.11–10.15 to include the complete
* functionality of the payroll application of Figs. 10.4–10.9. The application
* should still process two Invoice objects, but now should process one object
* of each of the four Employee subclasses. If the object currently being
* processed is a Base- PlusCommissionEmployee, the application should increase
* the BasePlusCommissionEmployee’s base salary by 10%. Finally, the application
* should output the payment amount for each object. Complete the following
* steps to create the new application: a) Modify classes HourlyEmployee (Fig.
* 10.6) and CommissionEmployee (Fig. 10.7) to place them in the Payable
* hierarchy as subclasses of the version of Employee (Fig. 10.13) that
* implements Payable. [Hint: Change the name of method earnings to
* getPaymentAmount in each subclass so that the class satisfies its inherited
* contract with interface Payable.] b) Modify class BasePlusCommissionEmployee
* (Fig. 10.8) such that it extends the version of class CommissionEmployee
* created in part (a). c) Modify PayableInterfaceTest (Fig. 10.15) to
* polymorphically process two Invoices, one SalariedEmployee, one
* HourlyEmployee, one CommissionEmployee and one Base- PlusCommissionEmployee.
* First output a String representation of each Payable object. Next, if an
* object is a BasePlusCommissionEmployee, increase its base salary by 10%.
* Finally, output the payment amount for each Payable object.
*
* @author Pandenghuang@163.com
* @Date Jan 7, 2019, 2:07:26 PM
*
*/
public class PayableInterfaceTest
{
public static void main(String[] args)
{
// create four-element Payable array
Payable[] payableObjects = new Payable[6];
// populate array with objects that implement Payable
payableObjects[0] = new Invoice("01234", "seat", 2, 375.00);
payableObjects[1] = new Invoice("56789", "tire", 4, 79.95);
payableObjects[2] =
new SalariedEmployee("John", "Smith", "111-11-1111", 800.00);
payableObjects[3] =
new HourlyEmployee("Lisa", "Barnes", "888-88-8888", 40,50);
payableObjects[4] =
new CommissionEmployee("Andrew", "Brown", "999-99-9999", 100000,0.08);
payableObjects[5] =
new BasePlusCommissionEmployee("Andy", "Jobs", "666-66-6666", 100000.0,0.08,600.0);
System.out.println(
"Invoices and Employees processed polymorphically:");
// generically process each element in array payableObjects
for (Payable currentPayable : payableObjects)
{
// output currentPayable and its appropriate payment amount
System.out.printf("%n%s %n%s: $%,.2f%n",
currentPayable.toString(), // could invoke implicitly
"payment due", currentPayable.getPaymentAmount());
// determine whether element is a BasePlusCommissionEmployee
if (currentPayable instanceof BasePlusCommissionEmployee)
{
// downcast Employee reference to
// BasePlusCommissionEmployee reference
BasePlusCommissionEmployee employee =
(BasePlusCommissionEmployee) currentPayable;
employee.setBaseSalary(1.10 * employee.getBaseSalary());
System.out.printf(
"new base salary with 10%% increase is: $%,.2f",
employee.getBaseSalary());
}
}
} // end main
} // end class PayableInterfaceTest
2. 实体类
1)Payable接口
// Fig. 10.11: Payable.java
// Payable interface declaration.
public interface Payable
{
double getPaymentAmount(); // calculate payment; no implementation
}
2) Invoice类
// Fig. 10.12: Invoice.java
// Invoice class that implements Payable.
public class Invoice implements Payable
{
private final String partNumber;
private final String partDescription;
private int quantity;
private double pricePerItem;
// constructor
public Invoice(String partNumber, String partDescription, int quantity,
double pricePerItem)
{
if (quantity < 0) // validate quantity
throw new IllegalArgumentException("Quantity must be >= 0");
if (pricePerItem < 0.0) // validate pricePerItem
throw new IllegalArgumentException(
"Price per item must be >= 0");
this.quantity = quantity;
this.partNumber = partNumber;
this.partDescription = partDescription;
this.pricePerItem = pricePerItem;
} // end constructor
// get part number
public String getPartNumber()
{
return partNumber; // should validate
}
// get description
public String getPartDescription()
{
return partDescription;
}
// set quantity
public void setQuantity(int quantity)
{
if (quantity < 0) // validate quantity
throw new IllegalArgumentException("Quantity must be >= 0");
this.quantity = quantity;
}
// get quantity
public int getQuantity()
{
return quantity;
}
// set price per item
public void setPricePerItem(double pricePerItem)
{
if (pricePerItem < 0.0) // validate pricePerItem
throw new IllegalArgumentException(
"Price per item must be >= 0");
this.pricePerItem = pricePerItem;
}
// get price per item
public double getPricePerItem()
{
return pricePerItem;
}
// return String representation of Invoice object
@Override
public String toString()
{
return String.format("%s: %n%s: %s (%s) %n%s: %d %n%s: $%,.2f",
"invoice", "part number", getPartNumber(), getPartDescription(),
"quantity", getQuantity(), "price per item", getPricePerItem());
}
// method required to carry out contract with interface Payable
@Override
public double getPaymentAmount()
{
return getQuantity() * getPricePerItem(); // calculate total cost
}
} // end class Invoice
3). Employee类
// Fig. 10.13: Employee.java
// Employee abstract superclass that implements Payable.
public abstract class Employee implements Payable
{
private final String firstName;
private final String lastName;
private final String socialSecurityNumber;
// constructor
public Employee(String firstName, String lastName,
String socialSecurityNumber)
{
this.firstName = firstName;
this.lastName = lastName;
this.socialSecurityNumber = socialSecurityNumber;
}
// return first name
public String getFirstName()
{
return firstName;
}
// return last name
public String getLastName()
{
return lastName;
}
// return social security number
public String getSocialSecurityNumber()
{
return socialSecurityNumber;
}
// return String representation of Employee object
@Override
public String toString()
{
return String.format("%s %s%nsocial security number: %s",
getFirstName(), getLastName(), getSocialSecurityNumber());
}
// Note: We do not implement Payable method getPaymentAmount here so
// this class must be declared abstract to avoid a compilation error.
} // end abstract class Employee
4). SalariedEmployee类
// Fig. 10.14: SalariedEmployee.java
// SalariedEmployee class that implements interface Payable.
// method getPaymentAmount.
public class SalariedEmployee extends Employee
{
private double weeklySalary;
// constructor
public SalariedEmployee(String firstName, String lastName,
String socialSecurityNumber, double weeklySalary)
{
super(firstName, lastName, socialSecurityNumber);
if (weeklySalary < 0.0)
throw new IllegalArgumentException(
"Weekly salary must be >= 0.0");
this.weeklySalary = weeklySalary;
}
// set salary
public void setWeeklySalary(double weeklySalary)
{
if (weeklySalary < 0.0)
throw new IllegalArgumentException(
"Weekly salary must be >= 0.0");
this.weeklySalary = weeklySalary;
}
// return salary
public double getWeeklySalary()
{
return weeklySalary;
}
// calculate earnings; implement interface Payable method that was
// abstract in superclass Employee
@Override
public double getPaymentAmount()
{
return getWeeklySalary();
}
// return String representation of SalariedEmployee object
@Override
public String toString()
{
return String.format("salaried employee: %s%n%s: $%,.2f",
super.toString(), "weekly salary", getWeeklySalary());
}
} // end class SalariedEmployee
5). HourlyEmployee类
// Fig. 10.6: HourlyEmployee.java
// HourlyEmployee class extends Employee.
public class HourlyEmployee extends Employee
{
private double wage; // wage per hour
private double hours; // hours worked for week
// constructor
public HourlyEmployee(String firstName, String lastName,
String socialSecurityNumber, double wage, double hours)
{
super(firstName, lastName, socialSecurityNumber);
if (wage < 0.0) // validate wage
throw new IllegalArgumentException(
"Hourly wage must be >= 0.0");
if ((hours < 0.0) || (hours > 168.0)) // validate hours
throw new IllegalArgumentException(
"Hours worked must be >= 0.0 and <= 168.0");
this.wage = wage;
this.hours = hours;
}
// set wage
public void setWage(double wage)
{
if (wage < 0.0) // validate wage
throw new IllegalArgumentException(
"Hourly wage must be >= 0.0");
this.wage = wage;
}
// return wage
public double getWage()
{
return wage;
}
// set hours worked
public void setHours(double hours)
{
if ((hours < 0.0) || (hours > 168.0)) // validate hours
throw new IllegalArgumentException(
"Hours worked must be >= 0.0 and <= 168.0");
this.hours = hours;
}
// return hours worked
public double getHours()
{
return hours;
}
// calculate earnings; override abstract method earnings in Employee
@Override
public double getPaymentAmount()
{
if (getHours() <= 40) // no overtime
return getWage() * getHours();
else
return 40 * getWage() + (getHours() - 40) * getWage() * 1.5;
}
// return String representation of HourlyEmployee object
@Override
public String toString()
{
return String.format("hourly employee: %s%n%s: $%,.2f; %s: %,.2f",
super.toString(), "hourly wage", getWage(),
"hours worked", getHours());
}
} // end class HourlyEmployee
6)CommissionEmployee类
public class CommissionEmployee extends Employee
{
private double grossSales; // gross weekly sales
private double commissionRate; // commission percentage
// constructor
public CommissionEmployee(String firstName, String lastName,
String socialSecurityNumber, double grossSales,
double commissionRate)
{
super(firstName, lastName,socialSecurityNumber);
if (commissionRate <= 0.0 || commissionRate >= 1.0) // validate
throw new IllegalArgumentException(
"Commission rate must be > 0.0 and < 1.0");
if (grossSales < 0.0) // validate
throw new IllegalArgumentException("Gross sales must be >= 0.0");
this.grossSales = grossSales;
this.commissionRate = commissionRate;
}
// set gross sales amount
public void setGrossSales(double grossSales)
{
if (grossSales < 0.0) // validate
throw new IllegalArgumentException("Gross sales must be >= 0.0");
this.grossSales = grossSales;
}
// return gross sales amount
public double getGrossSales()
{
return grossSales;
}
// set commission rate
public void setCommissionRate(double commissionRate)
{
if (commissionRate <= 0.0 || commissionRate >= 1.0) // validate
throw new IllegalArgumentException(
"Commission rate must be > 0.0 and < 1.0");
this.commissionRate = commissionRate;
}
// return commission rate
public double getCommissionRate()
{
return commissionRate;
}
// calculate earnings; override abstract method earnings in Employee
@Override
public double getPaymentAmount()
{
return getCommissionRate() * getGrossSales();
}
// return String representation of CommissionEmployee object
@Override
public String toString()
{
return String.format("%s: %s%n%s: $%,.2f; %s: %.2f",
"commission employee", super.toString(),
"gross sales", getGrossSales(),
"commission rate", getCommissionRate());
}
} // end class CommissionEmployee
. 7) BasePlusComissionEmployee类
// Fig. 10.8: BasePlusCommissionEmployee.java
// BasePlusCommissionEmployee class extends CommissionEmployee.
public class BasePlusCommissionEmployee extends CommissionEmployee
{
private double baseSalary; // base salary per week
// constructor
public BasePlusCommissionEmployee(String firstName, String lastName,
String socialSecurityNumber, double grossSales,
double commissionRate, double baseSalary)
{
super(firstName, lastName, socialSecurityNumber,
grossSales, commissionRate);
if (baseSalary < 0.0) // validate baseSalary
throw new IllegalArgumentException("Base salary must be >= 0.0");
this.baseSalary = baseSalary;
}
// set base salary
public void setBaseSalary(double baseSalary)
{
if (baseSalary < 0.0) // validate baseSalary
throw new IllegalArgumentException("Base salary must be >= 0.0");
this.baseSalary = baseSalary;
}
// return base salary
public double getBaseSalary()
{
return baseSalary;
}
// calculate earnings; override method earnings in CommissionEmployee
@Override
public double getPaymentAmount()
{
return getBaseSalary() + super.getPaymentAmount();
}
// return String representation of BasePlusCommissionEmployee object
@Override
public String toString()
{
return String.format("%s %s; %s: $%,.2f",
"base-salaried", super.toString(),
"base salary", getBaseSalary());
}
} // end class BasePlusCommissionEmployee