By Tony Bevis on Friday, 13 October 2023
Category: Java

Java programming course: 8.3 Person utility class

In the previous lesson we discussed what utility classes are.

Person utility class

Now that you have a separate Utilities project containing the Gender enum, you can create the class called Person in the com.example.util package of Utilities:

With the Person class in place, you may naturally assume that you should modify the ZooKeeper and Visitor classes to each inherit from it, since they are both kinds of Person. This is a valid approach, of course, but there is an alternative way of utilising Person that you should also consider where instead of using inheritance you use composition.

Object composition simply means that one object is "composed of" another object, of a particular type. You have already used this approach several times, in fact. For example, the Person class is composed of two String objects and a Gender object, through its instance variables. Whereas inheritance describes an "is a" (or "is a type of") relationship, composition describes a "has a" (or "comprises") relationship.

You will now see how the two approaches, inheritance, and composition, compare when applied to the ZooKeeper class.

For each option, you need to import the com.example.util package.

Before making any changes however, it is suggested that you just read the following sections to understand the relative advantages and disadvantages of the two approaches.

Option 1: Inheritance

To change ZooKeeper to inherit from Person you have to use the extends keyword in the class header:

You would then need to remove the instance variables for name and address, and their associated methods setName(), getName(), setAddress() and getAddress().

You would then need to change the constructor to pass the name and address arguments to the superclass constructor:


This illustrates a particular disadvantage of inheritance – you are stuck with the attributes and methods you are inheriting. You could, of course, override the unwanted methods, but what should they do instead? Also, you may have other classes which use Person objects and rely on the value of the gender. Also consider the Visitor class: as well as not needing to inherit gender it also doesn't need to inherit address.

The main advantage of inheritance is that you don't have to duplicate the instance variables and methods in the subclass, so it does generally result in a smaller, cleaner class.

Option 2: Composition

To change ZooKeeper to use Person through composition rather than inheritance you instead define an instance variable for Person which can replace the attributes for name and address:

The constructor needs to replace the two String arguments for name and address with a Person object argument:


You would also need to change any client object that instantiates ZooKeeper objects to pass a single Person object rather than two String objects to the constructor.

You need a getter and setter method for the person attribute:


You should now remove the setName() and setAddress() methods since these are now modifiable through the setPerson() method. While you could remove the getName() and getAddress() retaining them would serve as a convenience for client objects. You would, however, need to modify them to forward to the person object, as follows:

The advantage of composition is that you can totally ignore any attributes that aren't needed, such as gender in the above case. The methods setGender() and getGender() are simply not available to be invoked. The main disadvantage is that you have to write some forwarding methods to the composed of object for the attributes you do want, although as you can see, they are typically very simple.

It may initially seem counter-intuitive to think of ZooKeeper as "having" a Person rather than "being" a type of Person, but another way to think about it is that is that of a Person "taking on the role" of a ZooKeeper. Likewise, if you use composition in the Visitor class, the Person is taking on the role of being a Visitor.

The discussion in the note-box above leads to a further advantage of composition over inheritance, in that if you declare that ZooKeeper and Visitor each inherit from Person then it is not possible for a particular Visitor to ever become a ZooKeeper, or for a ZooKeeper to ever be a Visitor. You would need to instantiate two separate objects (one ZooKeeper and one Visitor) to model this scenario even though they should be referring to the same person. This limitation does not occur with composition since you can instantiate a single Person object and assign it to both a ZooKeeper object and to a Visitor object. In other words, the Person is taking on two roles concurrently, that of being both a ZooKeeper and a Visitor.

Conclusion

Having discussed the two options, a decision needs to be made as to whether to use inheritance or composition. In view of the relative advantages and disadvantage this course takes the view that composition is a slightly preferred approach, and you should now modify the ZooKeeper as detailed above and then the Visitor class along identical lines.

The modified ZooKeeper class should look like this:

The modified Visitor class should look like this:


In ZooAdministrator you will need to import com.example.util and modify the methods createExampleZooKeepers() and createExampleVisitors():

In the next series of lessons we will discuss immutable classes and the Object class.

Next lesson: 9.1 Immutable classes and the Object class

Related Posts

Leave Comments