Webster's New World Dictionary defines encapsulation as:
"To enclose in or as if in a capsule"...
For modules and classes, encapsulation
encloses an implementation, exposing only an interface.
Purposes of Encapsulation:-
Avoid breaking client code when an implementation changes.
-
Support module or class abstraction by providing a simple interface to what may be
a complex implementation.
Breaking client code:- Design breaks:
If names or types used by the client change, the client's design breaks. This could happen because
the interface changes (we try very hard not to do that) or the client has references into the
implementation due to failures in encapsulation.
- Compile breaks:
If the size of the object changes, perhaps by adding a new private data member then the client must be recompiled.
If the text of the class declaration changes, perhaps to change the qualification of a type of a
private data member, and the client declares an object anywhere, then the client must be recompiled.
- Link breaks:
If the client:
-
accesses a class through an abstract interface, e.g., an abstract base class from which the class derives
-
does not directly create any instances of the class (would require the client to include class's declaration)
-
statically links to the class's object code
Then the client need not be recompiled when the class's implementation changes. However, the client
must be relinked to the new object code.
- Nothing breaks:
If all the conditions of the previous item are satisfied except that the client accesses the class through a
dynamic link library, which will be loaded at run-time, then changing a class's implementation breaks nothing!
Design Rules:
Classes and modules should hide their implementations behind simple user interfaces.
- Modules:
-
Export only const global data. Declare it in implementation file, Declare it extern in header file.
If you feel you must use non-const global data in a module, make it private by declaring only in implementation file
and qualify as static.
-
Private global functions qualify their return values with keyword static.
- Classes:
-
All member data must be private or protected. We occasionally make an exception
for constants and enumerations.
-
Make private any member function that requires knowledge of the design to use effectively or safely.
-
Avoid returning pointers. If the class design supports a part of abstraction by exposing some
properly encapsulated inner object then return a reference to the internal object instead of a pointer.
References allow the user to access the object. Pointers allow the user to access memory. Moreover,
clients must then understand your design to know if they should or should not call delete on the
pointer your class passed them.
There is one notable exception to this no pointer return rule. If your class has a creational function,
perhaps a static function that creates an instance of the class, or a function that creates an instance
of some other class. Then it is appropriate to return a pointer to the newly created object. The
client then must treat the creational function as a sophisticated form of new and assume management
of the object's storage. You, of course, must warn the user in your manual page.
Should every class be properly encapsulated? Not necessarily. If your design uses a class internal to some
other class, and never exposes it to clients, by declaring it in the implementation file rather than the class's header file,
then you cause no problems for your clients. However, now maintainers of your code have to be careful with
the unencapsulated inner class.