Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

AhmadLang / Java, How To Program, 2004

.pdf
Скачиваний:
630
Добавлен:
31.05.2015
Размер:
51.82 Mб
Скачать

errors), use inheritance, rather than the "copy-andpaste" approach, in situations where you want one class to "absorb" the instance variables and methods of another class.

Software Engineering Observation 9.5

With inheritance, the common instance variables and methods of all the classes in the hierarchy are declared in a superclass. When changes are required for these common features, software developers need only to make the changes in the superclasssubclasses then inherit the changes. Without inheritance, changes would need to be made to all the source code files that contain a copy of the code in question.

9.4.3. Creating a CommissionEmployeeBasePlusCommissionEmployee

Inheritance Hierarchy

Now we declare class BasePlusCommissionEmployee2 (Fig. 9.8), which extends class CommissionEmployee (Fig. 9.4). A BasePlusCommissionEmployee2 object is a CommissionEmployee (because inheritance passes on the capabilities of class CommissionEmployee), but class BasePlusCommissionEmployee2 also has instance variable baseSalary (Fig. 9.8, line 6). Keyword extends in line 4 of the class declaration indicates inheritance. As a subclass, BasePlusCommissionEmployee2 inherits the public and protected instance variables and methods of class CommissionEmployee. The constructor of class CommissionEmployee is not inherited. Thus, the public services of BasePlusCommissionEmployee2 include its constructor (lines 916), public methods inherited from class CommissionEmployee, method setBaseSalary (lines 1922), method getBaseSalary (lines 2528), method earnings (lines 3135) and method toString (lines 3847).

[Page 431]

Figure 9.8. private superclass members cannot be accessed in a subclass.

(This item is displayed on pages 431 - 432 in the print version)

1// Fig. 9.8: BasePlusCommissionEmployee2.java

2// BasePlusCommissionEmployee2 inherits from class CommissionEmployee.

4public class BasePlusCommissionEmployee2 extends CommissionEmployee

5

{

6

private double baseSalary; // base salary per week

7

 

8// six-argument constructor

9public BasePlusCommissionEmployee2( String first, String last,

10String ssn, double sales, double rate, double salary )

11{

12// explicit call to superclass CommissionEmployee constructor

13super( first, last, ssn, sales, rate );

14

15setBaseSalary( amount ); // validate and store base salary

16} // end six-argument BasePlusCommissionEmployee2 constructor

18// set base salary

19public void setBaseSalary( double salary )

20{

21baseSalary = ( salary < 0.0 ) ? 0.0 : salary;

22} // end method setBaseSalary

23

24// return base salary

25public double getBaseSalary()

26{

27return baseSalary;

28 } // end method getBaseSalary

29

30// calculate earnings

31public double earnings()

32{

33// not allowed: commissionRate and grossSales private in superclass

34return baseSalary + ( commissionRate * grossSales );

35} // end method earnings

36

37// return String representation of BasePlusCommissionEmployee2

38public String toString()

39{

40// not allowed: attempts to access private superclass members

41return String.format(

42"%s: %s %s\n%s: %s\n%s: %.2f\n%s: %.2f\n%s: %.2f",

43"base-salaried commission employee", firstName, lastName,

44"social security number", socialSecurityNumber,

45"gross sales", grossSales, "commission rate", commissionRate,

46"base salary", baseSalary );

47} // end method toString

48} // end class BasePlusCommissionEmployee2

BasePlusCommissionEmployee2.java:34: commissionRate has private access in CommissionEmployee

return baseSalary + ( commissionRate * grossSales );

^

BasePlusCommissionEmployee2.java:34: grossSales has private access in CommissionEmployee

return baseSalary + ( commissionRate * grossSales );

^

BasePlusCommissionEmployee2.java:43: firstName has private access in CommissionEmployee

"base-salaried commission employee", firstName, lastName,

^

BasePlusCommissionEmployee2.java:43: lastName has private access in CommissionEmployee

"base-salaried commission employee", firstName, lastName,

^

BasePlusCommissionEmployee2.java:44: socialSecurityNumber has private access in CommissionEmployee

"social security number", socialSecurityNumber,

^

BasePlusCommissionEmployee2.java:45: grossSales has private access in CommissionEmployee

"gross sales", grossSales, "commission rate", commissionRate,

^

BasePlusCommissionEmployee2.java:45: commissionRate has private access in CommissionEmployee

"gross sales", grossSales, "commission rate", commissionRate,

^

7 errors

[Page 432]

Each subclass constructor must implicitly or explicitly call its superclass constructor to ensure that the instance variables inherited from the superclass are initialized properly. BasePlusCommissionEmployee2's sixargument constructor (lines 916) explicitly calls class CommissionEmployee's five-argument constructor to initialize the superclass portion of a BasePlusCommissionEmployee2 object (i.e., variables firstName,

lastName, socialSecurityNumber, grossSales and commissionRate). Line 13 in

BasePlusCommissionEmployee2's six-argument constructor invokes the CommissionEmployee's five-argument constructor (declared at lines 1322 of Fig. 9.4) by using the superclass constructor call syntaxkeyword super, followed by a set of parentheses containing the superclass constructor arguments. The arguments first, last, ssn, sales and rate are used to initialize superclass members firstName, lastName,

socialSecurityNumber, grossSales and commissionRate, respectively. If BasePlusCommissionEmployee2's constructor did not invoke CommissionEmployee's constructor explicitly, Java would attempt to invoke class

CommissionEmployee's no-argument or default constructorbut the class does not have such a constructor, so the compiler would issue an error. The explicit superclass constructor call on line 13 must be the first statement in the subclass constructor's body. Also, when a superclass contains a no-argument constructor, you can use super() to call that constructor explicitly, but this is rarely done.

[Page 433]

Common Programming Error 9.2

A compilation error occurs if a subclass constructor calls one of its superclass constructors with arguments that do not match exactly the number and types of parameters specified in one of the superclass constructor declarations.

The compiler generates errors for line 34 of Fig. 9.8 because superclass CommissionEmployee's instance

variables commissionRate and grossSales are privatesubclass BasePlusCommissionEmployee2's methods are not allowed to access superclass CommissionEmployee's private instance variables. Note that we used red text in Fig. 9.8 to indicate erroneous code. The compiler issues additional errors at lines 4345 of

BasePlusCommissionEmployee2's toString method for the same reason. The errors in BasePlusCommissionEmployee2 could have been prevented by using the get methods inherited from class

CommissionEmployee. For example, line 34 could have used getCommissionRate and getGrossSales to access CommissionEmployee's private instance variables commissionRate and grossSales, respectively. Lines 4345 also could have used appropriate get methods to retrieve the values of the superclass's instance variables.

9.4.4. CommissionEmployeeBasePlusCommissionEmployee

Inheritance Hierarchy Using protected Instance Variables

To enable class BasePlusCommissionEmployee to directly access superclass instance variables firstName,

lastName, socialSecurityNumber, grossSales and commissionRate, we can declare those members as protected in the superclass. As we discussed in Section 9.3, a superclass's protected members are inherited by all subclasses of that superclass. Class CommissionEmployee2 (Fig. 9.9) is a modification of class

CommissionEmployee (Fig. 9.4) that declares instance variables firstName, lastName,

socialSecurityNumber, grossSales and commissionRate as protected (Fig. 9.9, lines 610) rather than private. Other than the change in the class name (and thus the change in the constructor name) to CommissionEmployee2, the rest of the class declaration in Fig. 9.9 is identical to that of Fig. 9.4.

[Page 435]

Figure 9.9. CommissionEmployee2 with protected instance variables.

 

 

(This item is displayed on pages 433 - 435 in the print version)

1

//

Fig. 9.9: CommissionEmployee2.java

2

//

CommissionEmployee2 class represents a commission employee.

3

 

 

4public class CommissionEmployee2

5{

6protected String firstName;

7protected String lastName;

8protected String socialSecurityNumber;

9protected double grossSales; // gross weekly sales

10protected double commissionRate; // commission percentage

12// five-argument constructor

13public CommissionEmployee2 ( String first, String last, String ssn,

14double sales, double rate )

15{

16// implicit call to Object constructor occurs here

17firstName = first;

18lastName = last;

19socialSecurityNumber = ssn;

20setGrossSales( sales ); // validate and store gross sales

21setCommissionRate( rate ); // validate and store commission rate

22} // end five-argument CommissionEmployee2 constructor

23

24// set first name

25public void setFirstName( String first )

26{

27firstName = first;

28} // end method setFirstName

29

30// return first name

31public String getFirstName()

32{

33return firstName;

34} // end method getFirstName

36// set last name

37public void setLastName( String last )

38{

39lastName = last;

40} // end method setLastName

42// return last name

43public String getLastName()

44{

45return lastName;

46} // end method getLastName

48// set social security number

49public void setSocialSecurityNumber( String ssn )

50{

51socialSecurityNumber = ssn; // should validate

52} // end method setSocialSecurityNumber

53

54// return social security number

55public String getSocialSecurityNumber()

56{

57return socialSecurityNumber;

58} // end method getSocialSecurityNumber

60// set gross sales amount

61public void setGrossSales( double sales )

62{

63grossSales = ( sales < 0.0 ) ? 0.0 : sales;

64} // end method setGrossSales

65

66// return gross sales amount

67public double getGrossSales()

68{

69return grossSales;

70} // end method getGrossSales

72// set commission rate

73public void setCommissionRate( double rate )

74

{

 

75

 

commissionRate = ( rate > 0.0 && rate < 1.0 ) ? rate : 0.0;

76

}

// end method setCommissionRate

77

 

 

78// return commission rate

79public double getCommissionRate()

80{

81return commissionRate;

82} // end method getCommissionRate

84// calculate earnings

85public double earnings()

86{

87return commissionRate * grossSales;

88} // end method earnings

89

90// return String representation of CommissionEmployee2 object

91public String toString()

92{

93return String.format( "%s: %s %s\n%s: %s\n%s: %.2f\n%s: %.2f",

94"commission employee", firstName, lastName,

95"social security number", socialSecurityNumber,

96"gross sales", grossSales,

97"commission rate", commissionRate );

98} // end method toString

99} // end class CommissionEmployee2

We could have declared the superclass CommissionEmployee2's instance variables firstName, lastName,

socialSecurityNumber, grossSales and commissionRate as public to enable subclass

BasePlusCommissionEmployee2 to access the superclass instance variables. However, declaring public instance variables is poor software engineering because it allows unrestricted access to the instance variables, greatly increasing the chance of errors. With protected instance variables, the subclass gets access to the instance variables, but classes that are not subclasses and classes that are not in the same package cannot access these variables directly. Recall that protected class members are also visible to other classes in the same package.

Class BasePlusCommissionEmployee3 (Fig. 9.10) is a modification of class BasePlusCommissionEmployee2

(Fig. 9.8) that extends CommissionEmployee2 (line 5) rather than class CommissionEmployee. Objects of class

BasePlusCommissionEmployee3 inherit CommissionEmployee2's protected instance variables firstName,

lastName, socialSecurityNumber, grossSales and commissionRateall these variables are now protected members of BasePlusCommissionEmployee3. As a result, the compiler does not generate errors when compiling line 32 of method earnings and lines 4042 of method toString. If another class extends

BasePlusCommissionEmployee3, the new subclass also inherits the protected members.

[Page 436]

Figure 9.10. BasePlusCommissionEmployee3 inherits protected instance variables from CommissionEmployee2.

1

// Fig. 9

.10: BasePlusCommissionEmployee3.java

2

//

BasePlusCommissionEmployee3 inherits from

CommissionEmployee2 and has

3

//

access

to CommissionEmployee2's protected

members.

4

 

 

 

 

5public class BasePlusCommissionEmployee3 extends CommissionEmployee2

6{

7

private double baseSalary; // base salary per week

8

 

9// six-argument constructor

10public BasePlusCommissionEmployee3( String first, String last,

11String ssn, double sales, double rate, double salary )

12{

13super( first, last, ssn, sales, rate );

14setBaseSalary( salary ); // validate and store base salary

15} // end six-argument BasePlusCommissionEmployee3 constructor

17// set base salary

18public void setBaseSalary( double salary )

19{

20baseSalary = ( salary < 0.0 ) ? 0.0 : salary;

21} // end method setBaseSalary

22

23// return base salary

24public double getBaseSalary()

25{

26return baseSalary;

27} // end method getBaseSalary

29// calculate earnings

30public double earnings()

31{

32return baseSalary + ( commissionRate * grossSales );

33} // end method earnings

34

35// return String representation of BasePlusCommissionEmployee3

36public String toString()

37{

38return String.format(

39"%s: %s %s\n%s: %s\n%s: %.2f\n%s: %.2f\n%s: %.2f",

40"base-salaried commission employee", firstName, lastName,

41"social security number", socialSecurityNumber,

42"gross sales", grossSales, "commission rate", commissionRate,

43"base salary", baseSalary );

44} // end method toString

45} // end class BasePlusCommissionEmployee3

Class BasePlusCommissionEmployee3 does not inherit class CommissionEmployee2's constructor. However, class BasePlusCommissionEmployee3's six-argument constructor (lines 1015) calls class CommissionEmployee2's five-argument constructor explicitly. BasePlusCommissionEmployee3's six-argument constructor must explicitly call the five-argument constructor of class CommissionEmployee2, because CommissionEmployee2 does not provide a no-argument constructor that could be invoked implicitly.

[Page 437]

Figure 9.11 uses a BasePlusCommissionEmployee3 object to perform the same tasks that Fig. 9.7 performed on a BasePlusCommissionEmployee object (Fig. 9.6). Note that the outputs of the two programs are identical. Although we declared class BasePlusCommissionEmployee without using inheritance and declared class BasePlusCommissionEmployee3 using inheritance, both classes provide the same functionality. The source code for class BasePlusCommissionEmployee3, which is 45 lines, is considerably shorter than that for class BasePlusCommissionEmployee, which is 115 lines, because class BasePlusCommissionEmployee3 inherits most of its functionality from CommissionEmployee2, whereas class BasePlusCommissionEmployee inherits only class Object's functionality. Also, there is now only one copy of the commission employee functionality declared in class CommissionEmployee2. This makes the code easier to maintain, modify and debug, because the code related to a commission employee exists only in class CommissionEmployee2.

[Page 438]

Figure 9.11. protected superclass members inherited into subclass

BasePlusCommissionEmployee3.

(This item is displayed on pages 437 - 438 in the print version)

1// Fig. 9.11: BasePlusCommissionEmployeeTest3.java

2// Testing class BasePlusCommissionEmployee3.

3

4public class BasePlusCommissionEmployeeTest3

5{

6 public static void main( String args[] )

7{

8// instantiate BasePlusCommissionEmployee3 object

9BasePlusCommissionEmployee3 employee =

10new BasePlusCommissionEmployee3(

11"Bob", "Lewis", "333-33-3333", 5000, .04, 300 );

13// get base-salaried commission employee data

14System.out.println(

15"Employee information obtained by get methods: \n" );

16System.out.printf( "%s %s\n", "First name is",

17employee.getFirstName() );

18System.out.printf( "%s %s\n", "Last name is",

19employee.getLastName() );

20System.out.printf( "%s %s\n", "Social security number is",

21employee.getSocialSecurityNumber() );

22System.out.printf( "%s %.2f\n", "Gross sales is",

23employee.getGrossSales() );

24System.out.printf( "%s %.2f\n", "Commission rate is",

25employee.getCommissionRate() );

26System.out.printf( "%s %.2f\n", "Base salary is",

27employee.getBaseSalary() );

28

29 employee.setBaseSalary( 1000 ); // set base salary 30

31System.out.printf( "\n%s:\n\n%s\n",

32"Updated employee information obtained by toString",

33employee.toString() );

34} // end main

35} // end class BasePlusCommissionEmployeeTest3

Employee information obtained by get methods:

First name is Bob

Last name is Lewis

Social security number is 333-33-3333

Gross sales is 5000.00

Commission rate is 0.04

Base salary is 300.00

Updated employee information obtained by toString:

base-salaried commission employee: Bob Lewis social security number: 333-33-3333

gross sales: 5000.00 commission rate: 0.04 base salary: 1000.00

In this example, we declared superclass instance variables as protected so that subclasses could inherit them. Inheriting protected instance variables slightly increases performance, because we can directly access the variables in the subclass without incurring the overhead of a set or get method call. In most cases, however, it is better to use private instance variables to encourage proper software engineering, and leave code optimization issues to the compiler. Your code will be easier to maintain, modify and debug.

Using protected instance variables creates several potential problems. First, the subclass object can set an inherited variable's value directly without using a set method. Therefore, a subclass object can assign an invalid value to the variable, thus leaving the object in an inconsistent state. For example, if we were to declare CommissionEmployee3's instance variable grossSales as protected, a subclass object (e.g., BasePlusCommissionEmployee) could then assign a negative value to grossSales. The second problem with using protected instance variables is that subclass methods are more likely to be written so that they depend on the superclass's data implementation. In practice, subclasses should depend only on the superclass services (i.e., non-private methods) and not on the superclass data implementation. With protected instance variables in the superclass, we may need to modify all the subclasses of the superclass if the superclass implementation changes. For example, if for some reason we were to change the names of instance variables firstName and lastName to first and last, then we would have to do so for all occurrences in which a subclass directly references superclass instance variables firstName and lastName. In such a case, the software is said to be fragile or brittle, because a small change in the superclass can "break" subclass implementation. The programmer should be able to change the superclass implementation while still providing the same services to the subclasses. (Of course, if the superclass services change, we must reimplement our subclasses.) A third problem is that a class's protected members are visible to all classes in the same package as the class containing the protected membersthis is not always desirable.

[Page 439]

Software Engineering Observation 9.6

Use the protected access modifier when a superclass should provide a method only to its subclasses and other classes in the same package, but not to other clients.

Software Engineering Observation 9.7

Declaring superclass instance variables private (as opposed to protected) enables the superclass implementation of these instance variables to change without affecting subclass implementations.

Error-Prevention Tip 9.1

When possible, do not include protected instance variables in a superclass. Instead, include non-private methods that access private instance variables. This will ensure that objects of the class maintain consistent states.

9.4.5. CommissionEmployeeBasePlusCommissionEmployee

Inheritance Hierarchy Using private Instance Variables

We now reexamine our hierarchy once more, this time using the best software engineering practices. Class

CommissionEmployee3 (Fig. 9.12) declares instance variables firstName, lastName, socialSecurityNumber, grossSales and commissionRate as private (lines 610) and provides public methods setFirstName,

getFirstName, setLastName, getLastName, setSocialSecurityNumber, getSocialSecurityNumber,

setGrossSales, getGrossSales, setCommissionRate, getCommissionRate, earnings and toString for manipulating these values. Note that methods earnings (lines 8588) and toString (lines 9198) 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 modificationonly the bodies of the get and set methods that directly manipulate the instance variables will need to change. Note that these changes occur solely within the superclassno changes to the subclass are needed. Localizing the effects of changes like this is a good software engineering practice. Subclass BasePlusCommissionEmployee4 (Fig. 9.13) inherits CommissionEmployee3's non-private methods and can access the private superclass members via those methods.

[Page 441]

Figure 9.12. CommissionEmployee3 class uses methods to manipulate its private instance variables.

(This item is displayed on pages 439 - 441 in the print version)

1

//

Fig. 9.12: CommissionEmployee3.java

2

//

CommissionEmployee3 class represents a commission employee.

3

 

 

4public class CommissionEmployee3

5{

6private String firstName;

7private String lastName;

8private String socialSecurityNumber;

9private double grossSales; // gross weekly sales

10private double commissionRate; // commission percentage

12// five-argument constructor

13public CommissionEmployee3( String first, String last, String ssn,

14double sales, double rate )

15{

16// implicit call to Object constructor occurs here

17firstName = first;

18lastName = last;

19socialSecurityNumber = ssn;

20setGrossSales( sales ); // validate and store gross sales

21setCommissionRate( rate ); // validate and store commission rate

22} // end five-argument CommissionEmployee3 constructor

23

24// set first name

25public void setFirstName( String first )

26{

27firstName = first;

28} // end method setFirstName

30// return first name

31public String getFirstName()

32{

33return firstName;

34} // end method getFirstName

36// set last name

37public void setLastName( String last )

38{

39lastName = last;

40} // end method setLastName

42// return last name

43public String getLastName()

44{

45return lastName;

46} // end method getLastName

48// set social security number

49public void setSocialSecurityNumber( String ssn )

50{

51socialSecurityNumber = ssn; // should validate

52} // end method setSocialSecurityNumber

53

54// return social security number

55public String getSocialSecurityNumber()

56{

57return socialSecurityNumber;

58} // end method getSocialSecurityNumber

60// set gross sales amount

61public void setGrossSales( double sales )

62{

63grossSales = ( sales < 0.0 ) ? 0.0 : sales;

64} // end method setGrossSales

65

66// return gross sales amount

67public double getGrossSales()

68{

69return grossSales;

70} // end method getGrossSales

72// set commission rate

73public void setCommissionRate( double rate )

74

{

 

75

 

commissionRate = ( rate > 0.0 && rate < 1.0 ) ? rate : 0.0;

76

}

// end method setCommissionRate

77

 

 

78// return commission rate

79public double getCommissionRate()

80{

81return commissionRate;

82} // end method getCommissionRate

84// calculate earnings

85public double earnings()

86{

87return getCommissionRate() * getGrossSales();

88} // end method earnings

89

90// return String representation of CommissionEmployee3 object

91public String toString()

92{

93return String.format( "%s: %s %s\n%s: %s\n%s: %.2f\n%s: %.2f",

94"commission employee", getFirstName(), getLastName(),

95"social security number", getSocialSecurityNumber(),

96"gross sales", getGrossSales(),

97"commission rate", getCommissionRate() );

98} // end method toString

99} // end class CommissionEmployee3

Figure 9.13. BasePlusCommissionEmployee4 class extends

CommissionEmployee3, which provides only private instance variables.

(This item is displayed on page 442 in the print version)

1

//

Fig.

9.13: BasePlusCommissionEmployee4.java

 

2

// BasePlusCommissionEmployee4 class inherits from

CommissionEmployee3 and

3

// accesses CommissionEmployee3's private data via

CommissionEmployee3's

4

//

public

methods.

 

5

 

 

 

 

6public class BasePlusCommissionEmployee4 extends CommissionEmployee3

7{

8

private double baseSalary; // base salary per week

9

 

10// six-argument constructor

11public BasePlusCommissionEmployee4( String first, String last,

12String ssn, double sales, double rate, double salary )

13{

14super( first, last, ssn, sales, rate );

15setBaseSalary( salary ); // validate and store base salary

16} // end six-argument BasePlusCommissionEmployee4 constructor

18// set base salary

19public void setBaseSalary( double salary )

20{

21baseSalary = ( salary < 0.0 ) ? 0.0 : salary;

22} // end method setBaseSalary

23

24// return base salary

25public double getBaseSalary()

26{

27return baseSalary;

28} // end method getBaseSalary

30// calculate earnings

31public double earnings()

32{

33return getBaseSalary() + super.earnings();

34} // end method earnings

35

36// return String representation of BasePlusCommissionEmployee4

37public String toString()

38{

39return String.format( "%s %s\n%s: %.2f", "base-salaried",

40super.toString(), "base salary", getBaseSalary() );

41} // end method toString

42} // end class BasePlusCommissionEmployee4

Class BasePlusCommissionEmployee4 (Fig. 9.13) has several changes to its method implementations that distinguish it from class BasePlusCommissionEmployee3 (Fig. 9.10). Methods earnings (Fig. 9.13, lines 3134) and toString (lines 3741) 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.

Class BasePlusCommissionEmployee4's earnings method (Fig. 9.13, lines 3134) overrides class CommissionEmployee3's earnings method (Fig. 9.12, lines 8588) to calculate the earnings of a base-salaried commission employee. The new version obtains the portion of the employee's earnings based on commission alone by calling CommissionEmployee3's earnings method with the expression super.earnings() (Fig. 9.13, line 33). BasePlusCommissionEmployee4's earnings method then adds the base salary to this value to calculate the total earnings of the employee. Note the syntax used to invoke an overridden superclass method from a subclassplace the keyword super and a dot (.) separator before the superclass method name. This method invocation is a good software-engineering practice: Recall from Software Engineering Observation 8.5 that if a method performs all or some of the actions needed by another method, call that method rather than duplicate its code. By having BasePlusCommissionEmployee4's earnings method invoke

CommissionEmployee3's earnings method to calculate part of a BasePlusCommissionEmployee4 object's earnings, we avoid duplicating the code and reduce code-maintenance problems.

[Page 442]