Scenario: You go to an ATM machine, swipe in using your atm card, and ask for your bank balance.
Before we take this scenario apart, let’s add another word to our dictionary:
A type specification is a named collection of defined responsibilities. In object oriented terms, a class is a type specification.
Now let us analyze this scenario.
We will need an ATM object to represent our ATM machine. The objects type specification is a class that defines two responsibilities (in our scenario):
- login – takes an ATM card and a pin number, and throws an exception if they do not match
- getBalance – returns the balance in the account corresponding to the ATM card
Look at the login responsibility. It involves the following steps:
- Read the ATM card number
- Call a validating service passing the card number and pin number entered by the user
- Receive the result from the service – valid login or not
- If validity is confirmed, start an ATM session
- Return the result to the caller
These steps are fairly complex. But they do not concern the entity that invokes the login responsibity of the ATM object. The invoking entity (human user) merely has an ATM card number and pin number, and needs to start an ATM session.
It’s the responsibility of the ATM object to validate these numbers before starting a new session, by performing the 5 steps that I mentioned above. So we encapsulate these 5 steps into a responsibility called login, which we define in the type specification (i.e. class) of the ATM object. Any entity that needs to login to a new session on an ATM object, may now invoke the login responsibility of the ATM object, passing valid card and pin numbers.
So we can explain encapsulation as defining a responsibility.
Now, let’s examine the getBalance responsibility. It could go like this:
- Make a call to some service, passing in the ATM card number
- Receive the balance amount from the service
- Return this balance to the caller
getBalance is a responsibility all by itself. It’s also a good example of data hiding. Data hiding is a form of encapsulation in which we define access to data as a responsibility.
So all data hiding is encapsulation, but not all encapsulation is data hiding. Go figure (think this through for yourself, it’s quite simple).
The getBalance responsibility is an example of data hiding in which information can only be retrieved. But often we need to control how the data is stored as well. So let us add two responsibilities to the ATM type specification: deposit and withdraw. The deposit responsibility would involve incrementing the balance by some amount. The withdraw responsibility is more work: decrementing the balance by some amount unless the balance is already zero; in which case, no amount would be decremented since a negative balance is meaningless. We need not worry about the business logic involved when depositing or withdrawing some amount, as these responsibilities belong to the ATM object, as defined in it’s type specification.
What is the difference between data hiding and returning status messages? In our ATM example, both login and getBalance return data. How can we tell that getBalance involves data hiding and login does not? Simple. The job of the getBalance responsibility is to retrieve data. Being a responsibility defined for retrieving data, it is an example of data hiding. But the login responsibility involves starting an authenticated session on an ATM object. The data it returns is only to let the caller know whether the responsibility was fulfilled or not. Since it’s primary responsibility isn’t retrieval of data, the login responsibility is not an example of data hiding.
The main advantage of any form of encapsulation (including data hiding) is that an entity need not know how to perform a given task. It only needs to know whose responsibility it is to perform that task.
For example, to retrieve my account balance, I don’t need to know the steps to do it. I only need to know that the ATM object is responsible for fetching my balance. If the steps to fetch account balances are changed, only the ATM type specification is affected; it’s getBalance responsibility must be modified to reflect the new procedure. Since no one else knows how to get an account balance, no other type specifications are affected. Only a small part of the system had to changed, so the chances of something breaking unexpectedly in our software model is greatly reduced.
Lastly, I’m always open to criticism. The comments section is open to the house.