The Accessor Methods pattern is one of the most commonly used patterns in the area of object-oriented programming. In fact, this pattern has been used in most of the examples discussed in this book for different patterns. In general, the values of different instance variables of an object, at a given point of time, constitute its state. The state of an object can be grouped into two categories — public and private. The public state of an object is available to different client objects to access, whereas the private state of an object is meant to be used internally by the object itself and not to be accessed by other objects.
Consider the class representation of a customer in Figure 6.1.
The instance variable ID is maintained separately and used internally by each Customer class instance and is not to be known by other objects. This makes the variable ID the private state of a Customer object to be used internally by the Customer object. On the other hand, variables such as name, SSN (Social Security Number) and the address make up the public state of the Customer object and are supposed to be used by client objects. In case of such an object, the Accessor Method pattern recommends:
Customer |
ID:int |
name:String |
SSN:String |
address:String |
Figure 6.1 Customer Class
There is no specific requirement for an accessor method to be named following a certain naming convention. But most commonly the following naming rules are followed:
• To access a non-Boolean instance variable:
• To access a Boolean instance variable:
The following Customer class example explains the usage of accessor methods.
Suppose that you are designing a Customer class as part of a large application. A generic representation of a customer in its simplest form can be designed as in Figure 6.2.
Applying the Accessor Method pattern, the set of accessor methods listed in Table 6.1 can be defined corresponding to each of the instance variables (Listing 6.1).
Figure 6.3 shows the resulting class structure.
Figure 6.2 Customer Representation
Table 6.1 List of Accessor Methods
Different client objects can access the object state variables using the accessor methods listed in Table 6.1. The Customer object itself can access its state variables directly, but using the accessor methods will greatly improve the maintainability of the Customer class code. This in turn contributes to the overall application maintainability.
Let us suppose that we need to add the following two new methods to the Customer class.
1. isValidCustomer — To check if the customer data is valid.
2. save — To save the customer data to a data file.
As can be seen from the Customer class implementation in Listing 6.2, the newly added methods access different instance variables directly. Different client objects can use the Customer class in this form without any difficulty. But when there is a change in the definition of any of the instance variables, it requires a change to the implementation of all the methods that access these instance variables directly. For example, if the address variable need to be changed from its current definition as a string to a StringBuffer or something different, then all methods that refer to the address variable directly needs to be altered.
Listing 6.1 Customer Class with Accessor Methods
public class Customer {
private String firstName;
private String lastName;
private String address;
private boolean active;
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getAddress() {
return address;
}
public boolean isActive() {
return active;
}
public void setFirstName(String newValue) {
firstName = newValue;
}
public void setLastName(String newValue) {
lastName = newValue;
}
public void setAddress(String newValue) {
address = newValue;
}
public void isActive(boolean newValue) {
active = newValue;
}
}
As an alternative approach, Customer object methods can be redesigned to access the object state through its accessor methods (Listing 6.3).
Customer |
firstName:String |
lastName:String |
active:boolean |
address:String |
________________________ |
getFirstName():String |
getLastName():String |
getAddress():String |
isActive():boolean |
setFirstName(newValue:String) |
setLastName(newValue:String) |
setAddress(newValue:String) |
setActive(newValue:boolean) |
Figure 6.3 Customer Class with Accessor Methods
In this approach, any change to the definition of any of the instance variables requires a change only to the implementation of the corresponding accessor methods. No changes are required for any other part of the class implementation and the class becomes more maintainable.
1. Design an Order class with accessor methods for its instance variables.
2. Identify the effect of using accessor methods when a class is subclassed.
Listing 6.2 Customer Class Directly Accessing Its Instance Variables
public class Customer {
…
…
public String getFirstName() {
return firstName;
}
…
…
public boolean isValidCustomer() {
if ((firstName.length() > 0) && (lastName.length() > 0) &&
(address.length() > 0))
return true;
return false;
}
public void save() {
String data =
firstName + ”," + lastName + ”," + address +
”," + active;
FileUtil futil = new FileUtil();
futil.writeToFile("customer.txt”,data, true, true);
}
}
Listing 6.3 Customer Class Using Accessor Methods to Access Its Instance Variables
public class Customer {
…
…
public String getFirstName() {
return firstName;
}
…
…
public boolean isValidCustomer() {
if ((getFirstName().length() > 0) &&
(getLastName().length() > 0) &&
(getAddress().length() > 0))
return true;
return false;
}
public void save() {
String data =
getFirstName() + ”," + getLastName() + ”," +
getAddress() + ”," + isActive();
FileUtil futil = new FileUtil();
futil.writeToFile("customer.txt”,data, true, true);
}
}
3.144.123.155