This is an old question but I came across a very helpful example to share with everyone.
You are correct that encapsulation is bundling of data with the methods that operate on that data. You are also correct that setting age
to private
means information hiding.
While the word "encapsulating" seems to imply "hiding", it does not "hide information" here.
The example from Encapsulation is not information hiding helps demonstrate (the difference between) encapsulation and information hiding.
The following are a Position
class and a utility class PositionUtility
that acts on it.
public class Position {
public double lat;
public double lon;
}
public class PositionUtility {
// the distance between the two Positions
public static double distance(Position pos1, Position pos2) { /* an implementation */ }
// the angle of Position pos1 towards Position pos2
public static double heading(Position pos1, Position pos2) { /* an implementation */ }
}
A typical use case for this code would be
Position myHouse = new Position();
myHouse.lat = 30.0;
myHouse.lon = 50.0;
Position coffeeShop = new Position();
coffeeShop.lat = 31.0;
coffeeShop.lon = 49.0;
double distance = PositionUtility.distance(myHouse, coffeeShop);
double heading = PositionUtility.heading(myHouse, coffeeShop);
The code has no encapsulation and information hiding. In order to adhere to encapsulation, you should let Position
itself handle the operations involving lat
and lon
.
public class Position {
public double lat;
public double lon;
// the distance between this Position and another Position pos
public double distance(Position pos) { /* an implementation */ }
// the angle of this Position towards another Position pos
public static double heading(Position pos) { /* an implementation */ }
}
Now you have encapsulation. Whenever you need to call distance
and heading
you do not need an external class (namely PositionUtility
) to access the fields in Position
.
However, other classes can still access and modify its public fields lat
, lon
. If you want to enforce certain constraints on these fields, those fields would need to be private
and modifying and retrieving them have to be done through getters/setters.
public class Position {
private double lat;
private double lon;
public Position(double lat, double lon) {
setLatitude(lat);
setLongitude(lon);
}
public void setLatitude(double lat) {
// some checking
this.lat = lat;
}
public void setLongitude(double lon) {
// some checking
this.lon = lon;
}
public double getLatitude() { return lat; }
public double getLongitude() { return lon; }
// ...
}
Now you achieve information hiding. The actual data structure used by Position
is no longer visible to other classes. Now, you could change your underlying implementation without affecting the users.
As an example, you can use phi
and theta
as your private fields and use radian instead of degree for calculation. A user using getLatitude()
and other getters/setters would not be aware that your internal data structure no longer contains lat
and lon
(and that should not matter to them anyway).
public class Position {
private double phi;
private double theta;
public Position(double lat, double lon) {
setLatitude(lat);
setLongitude(lon);
}
public void setLatitude(double lat) { setPhi(Math.toRadian(lat)); }
public void setLongitude(double lon) { setTheta(Math.toRadian(lon)); }
private void setPhi(double phi) {
// some checking
this.phi = phi;
}
private void setTheta(double theta) {
// some checking
this.theta = theta;
}
public double getLatitude() { return Math.toDegrees(phi); }
public double getLongitude() { return Math.toDegrees(theta); }
// ...
}
If information hiding hadn't been in place, this change in implementation would not be possible without affecting other classes, as they could be directly accessing the public lon
and lat
fields already.