Modify the other core system classes
Using the approach given above, it is the intention that the user interface classes only communicate with the core system through the ZooAdministrator class. At the moment there is nothing to prevent a user interface class from constructing a ZooKeeper object or calling one of its setter methods directly, because currently in ZooKeeper the constructor and methods are public. While you could take the view that you will simply not use ZooKeeper directly it is good practice to code the classes in such a way as it can be enforced.
In a larger organisation it is possible that there will be separate teams developing the core system and the user interface. By enforcing the way in which they communicate you can protect the integrity of the overall development.
The means of restricting access to the core classes is by taking advantage of package visibility. Starting with the ZooKeeper class, remove the public modifier on its constructor so it will use package (i.e., default) visibility:
public class ZooKeeper implements Emailable {
private Person person;
private Email email;
private BigDecimal salary;
ZooKeeper(Person person, Email email, BigDecimal salary){
this.person = person;
this.email = email;
this.salary = salary;
}
... rest of class omitted ...
The above change alone will prevent any class outside virtualzoo.core from ever instantiating a ZooKeeper object. ZooAdministator will be able to instantiate ZooKeeper objects, of course, since it is within the same package.
ZooKeeper objects can still be returned to the user interface, however, through ZooAdministrator's getZooKeepers() method. You should also prevent the user interface from changing the state of any ZooKeeper object except through ZooAdministrator's changeZooKeeper() method. To do this, remove the public modifier from all of ZooKeeper's setter methods, although the getter methods can remain public:
void setPerson(Person person) {
this.person = new Person(person); // uses copy constructor
}
void setEmail(Email email) {
this.email = email;
}
void setSalary(BigDecimal salary) {
this.salary = salary;
}
It is safe for the getter methods to remain public since except for getPerson() they each return immutable objects, and thus the user interface will be unable to modify any of their values. In the case of getPerson() a defensive copy is returned. It also means that once the user interface gets a reference to a ZooKeeper object it can easily access its attributes.
You should now update the other classes in the core package, as detailed below:
- In the
Animalclass, remove thepublicmodifier from the constructor and the methodssetName(),setGender(),setAge()andsetPen() - In the
Lion,MonkeyandPenguinclasses remove thepublicmodifier from both constructors in each of these three classes - In the
Visitorclass, remove thepublicmodifier from both of the constructors and from the methodssetPerson(),setEmail()andsetSponsoredAnimal() - In the
Penclass, remove thepublicmodifier from the constructor and from the methodsadd(),remove()andsetName()
The other classes in virtualzoo.core should also have the public modifier removed from their constructors and setter methods, and this is left as an optional exercise for the reader.
The classes are Booker, BookingCounter, FishBarrel, FishKeeper, HungryPenguin and VisitorBooker.
Comments