Information hiding is one key feature of Java in particular, and OO in general. It is not to be confused with encapsulation, since you can bundle data with your methods and not hide it at all. Even though these two (information hiding and encapsulation) are different, they are usually used together by making the attributes of your class private data members and providing getter (accessor) and setter (mutator) methods to them. Having said that, let us look at an example:
public class InformationHiding {
private Position position;
public InformationHiding(double latitude, double longitude)
throws IllegalArgumentException {
//make sure you have proper values for latitude and longitude
if (latitude >= -90 && latitude <=90 && longitude >= -180 && longitude <= 180) {
throw new IllegalArgumentException();
}
position = new Position(latitude, longitude);
}
public Position getPosition() {
return position;
}
}
Can you spot the problem with this code (beside the lack of synchronization)? Let's see how we can break the check for proper values of latitude and longitude:
InformationHiding inf = new InformationHiding(45, 120);
Position pos = inf.getPosition();
pos.latitude = -100; //illegal value
pos.longitude = 240; //illegal value
How can that be? We did make the position data member private? The problem is that we returned a reference to that member. This is a common mistake. Even when you generate the getter method from inside our IDE (i.e. Eclipse), it returns a reference to the attribute, rather than a copy to it. How can we fix this? Easy, just return a copy of the data member:
public Position getPosition() {
return new Position(position.latitude, position.longitude);
}
That's it! You could have used the clone method to make a copy of the object, but then some changes need to be made, like not implementing clone by using the constructor.
There are some cases when we do not need to return a copy of the data, namely when we deal with immutable objects (like Strings and the wrapper classes).
No comments:
Post a Comment