G.4.5. CommissionEmployeeBasePlusCommissionEmployee Inheritance Hierarchy Using private Instance Variables

Let’s reexamine our hierarchy once more, this time using good software engineering practices. Class CommissionEmployee (Fig. G.10) declares instance variables firstName, lastName, socialSecurityNumber, grossSales and commissionRate as private (lines 6–10) and provides public methods setFirstName, getFirstName, setLastName, getLastName, setSocialSecurityNumber, getSocialSecurityNumber, setGrossSales, getGrossSales, setCommissionRate, getCommissionRate, earnings and toString for manipulating these values. Methods earnings (lines 93–96) and toString (lines 99–107) use the class’s get methods to obtain the values of its instance variables. If we decide to change the instance-variable names, the earnings and toString declarations will not require modification—only the bodies of the get and set methods that directly manipulate the instance variables will need to change. These changes occur solely within the superclass—no changes to the subclass are needed. Localizing the effects of changes like this is a good software engineering practice.


 1      // Fig. G.10: CommissionEmployee.java
 2      // CommissionEmployee class uses methods to manipulate its
 3      // private instance variables.
 4      public class CommissionEmployee
 5      {
 6         private String firstName;                              
 7         private String lastName;                               
 8         private String socialSecurityNumber;                   
 9         private double grossSales; // gross weekly sales       
10         private double commissionRate; // commission percentage
11
12         // five-argument constructor
13         public CommissionEmployee( String first, String last, String ssn,
14            double sales, double rate )
15         {
16            // implicit call to Object constructor occurs here
17            firstName = first;
18            lastName = last;
19            socialSecurityNumber = ssn;
20            setGrossSales( sales ); // validate and store gross sales
21            setCommissionRate( rate ); // validate and store commission rate
22         } // end five-argument CommissionEmployee constructor
23
24         // set first name
25         public void setFirstName( String first )
26         {
27            firstName = first; // should validate
28         } // end method setFirstName
29
30         // return first name
31         public String getFirstName()
32         {
33            return firstName;
34         } // end method getFirstName
35
36         // set last name
37         public void setLastName( String last )
38         {
39            la5stName = last; // should validate
40         } // end method setLastName
41
42         // return last name
43         public String getLastName()
44         {
45            return lastName;
46         } // end method getLastName
47
48         // set social security number
49         public void setSocialSecurityNumber( String ssn )
50         {
51            socialSecurityNumber = ssn; // should validate
52         } // end method setSocialSecurityNumber
53
54         // return social security number
55         public String getSocialSecurityNumber()
56         {
57            return socialSecurityNumber;
58         } // end method getSocialSecurityNumber
59
60         // set gross sales amount
61         public void setGrossSales( double sales )
62         {
63            if ( sales >= 0.0 )
64               grossSales = sales;
65            else
66               throw new IllegalArgumentException(
67                  "Gross sales must be >= 0.0" );
68         } // end method setGrossSales
69
70         // return gross sales amount
71         public double getGrossSales()
72         {
73            return grossSales;
74         } // end method getGrossSales
75
76         // set commission rate
77         public void setCommissionRate( double rate )
78         {
79            if ( rate > 0.0 && rate < 1.0 )
80               commissionRate = rate;
81            else
82               throw new IllegalArgumentException(
83                  "Commission rate must be > 0.0 and < 1.0" );
84         } // end method setCommissionRate
85
86         // return commission rate
87         public double getCommissionRate()
88         {
89            return commissionRate;
90         } // end method getCommissionRate
91
92         // calculate earnings
93         public double earnings()
94         {
95            return getCommissionRate() * getGrossSales();
96         } // end method earnings
97
98         // return String representation of CommissionEmployee object
99         @Override // indicates that this method overrides a superclass method
100         public String toString()
101         {
102            return String.format( "%s: %s %s %s: %s %s: %.2f %s: %.2f",
103               "commission employee", getFirstName(), getLastName(),
104               "social security number", getSocialSecurityNumber(),
105               "gross sales", getGrossSales(),
106               "commission rate", getCommissionRate() );
107         } // end method toString
108      } // end class CommissionEmployee


Fig. G.10 | CommissionEmployee class uses methods to manipulate its private instance variables.

Subclass BasePlusCommissionEmployee (Fig. G.11) inherits CommissionEmployee’s non-private methods and can access the private superclass members via those methods. Class BasePlusCommissionEmployee has several changes that distinguish it from Fig. G.9. Methods earnings (lines 35–39) and toString (lines 42–47) each invoke method getBaseSalary to obtain the base salary value, rather than accessing baseSalary directly. If we decide to rename instance variable baseSalary, only the bodies of method setBaseSalary and getBaseSalary will need to change.


 1      // Fig. G.11: BasePlusCommissionEmployee.java
 2      // BasePlusCommissionEmployee class inherits from CommissionEmployee
 3      // and accesses the superclass's private data via inherited
 4      // public methods.
 5
 6      public class BasePlusCommissionEmployee extends CommissionEmployee
 7      {
 8         private double baseSalary; // base salary per week
 9
10         // six-argument constructor
11         public BasePlusCommissionEmployee( String first, String last,
12            String ssn, double sales, double rate, double salary )
13         {
14            super( first, last, ssn, sales, rate );
15            setBaseSalary( salary ); // validate and store base salary
16         } // end six-argument BasePlusCommissionEmployee constructor
17
18         // set base salary
19         public void setBaseSalary( double salary )
20         {
21            if ( salary >= 0.0 )
22               baseSalary = salary;
23            else
24               throw new IllegalArgumentException(
25                  "Base salary must be >= 0.0" );
26         } // end method setBaseSalary
27
28         // return base salary
29         public double getBaseSalary()
30         {
31            return baseSalary;
32         } // end method getBaseSalary
33
34         // calculate earnings
35         @Override // indicates that this method overrides a superclass method
36         public double earnings()
37         {
38            return getBaseSalary() + super.earnings();
39         } // end method earnings
40
41         // return String representation of BasePlusCommissionEmployee
42         @Override // indicates that this method overrides a superclass method
43         public String toString()
44         {
45            return String.format( "%s %s %s: %.2f", "base-salaried",
46               super.toString(), "base salary", getBaseSalary() );   
47         } // end method toString
48      } // end class BasePlusCommissionEmployee


Fig. G.11 | BasePlusCommissionEmployee class inherits from CommissionEmployee and accesses the superclass’s private data via inherited public methods.

Class BasePlusCommissionEmployee’s earnings Method

Method earnings (lines 35–39) overrides class CommissionEmployee’s earnings method (Fig. G.10, lines 93–96) to calculate a base-salaried commission employee’s earnings. The new version obtains the portion of the earnings based on commission alone by calling CommissionEmployee’s earnings method with super.earnings() (line 38), then adds the base salary to this value to calculate the total earnings. Note the syntax used to invoke an overridden superclass method from a subclass—place the keyword super and a dot (.) separator before the superclass method name. This method invocation is a good software engineering practice—if a method performs all or some of the actions needed by another method, call that method rather than duplicate its code. By having BasePlusCommissionEmployee’s earnings method invoke CommissionEmployee’s earnings method to calculate part of a BasePlusCommissionEmployee object’s earnings, we avoid duplicating the code and reduce code-maintenance problems. If we did not use “super.” then BasePlusCommissionEmployee’s earnings method would call itself rather than the superclass version. This would result in a phenomenon called infinite recursion, which would eventually cause the method-call stack to overflow—a fatal runtime error.

Class BasePlusCommissionEmployee’s toString Method

Similarly, BasePlusCommissionEmployee’s toString method (Fig. G.11, lines 42–47) overrides class CommissionEmployee’s toString method (Fig. G.10, lines 99–107) to return a String representation that’s appropriate for a base-salaried commission employee. The new version creates part of a BasePlusCommissionEmployee object’s String representation (i.e., the String "commission employee" and the values of class CommissionEmployee’s private instance variables) by calling CommissionEmployee’s toString method with the expression super.toString() (Fig. G.11, line 46). BasePlusCommissionEmployee’s toString method then outputs the remainder of a BasePlusCommissionEmployee object’s String representation (i.e., the value of class BasePlusCommissionEmployee’s base salary).

Testing Class BasePlusCommissionEmployee

Class BasePlusCommissionEmployeeTest performs the same manipulations on a BasePlusCommissionEmployee object as in Fig. G.7 and produces the same output, so we do not show it here. Although each BasePlusCommissionEmployee class you’ve seen behaves identically, the version in Fig. G.11 is the best engineered. By using inheritance and by calling methods that hide the data and ensure consistency, we’ve efficiently and effectively constructed a well-engineered class.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset