Sunday, June 19, 2011

Do You Get Encapsulation?

Nobody else is watching you read this blog, so for the next 15 or 30 minutes, do not Google, and do not reach for any CS books you've got handy. Use your memory and common sense, and let's see how much you really know about encapsulation.

First off, can you provide a decent explanation of the term? If you (somewhat dubiously) assert that it describes the bundling of data that describes the state of an object, along with methods (behaviour) that operate on that data, you get a grade of C. You are not wrong, but you have not completed the definition.

Let's feel our way towards a better definition of encapsulation. If I told you that accessors (setters and getters) sometimes break encapsulation, but not always, does that help? If I told you that default constructors are possibly a sign that encapsulation is broken, does that throw the switch?

Let's think about object state. We want the state of an object to always be valid and consistent. This means that a new object must start out that way (constructors), and stay that way over all operations (methods) done upon it. We have got a mechanism for ensuring that this is so, and you have likely now guessed what we call that mechanism.

Encapsulation is how we maintain valid and consistent object state.

Understanding this definition explains why a default constructor often breaks encapsulation. For starters, it may simply be available because the coder didn't bother to make it unavailable, or if having left it in, did not have it set valid member values that satisfy class invariants. A default constructor may sometimes be perfectly OK (e.g. there are no data members), but often it is not.

Understanding the definition of encapsulation also explains why sometimes setters and getters break encapsulation, and why sometimes they don't. There have been many blogs written where a pundit claims that any accessor breaks encapsulation. Well, no, that is incorrect. These same pundits opine that public accessors to a member are tantamount to making the member public. Well, no - that is also incorrect.

I should point out that I am using a restrictive definition of encapsulation. Many, if not most, definitions of the term bundle it together with the definition of information hiding. The two are frequently used interchangeably. Information hiding is usually defined as the separation of the contractual interface and its corresponding implementation. The purpose of information hiding is to permit implementation changes without affecting calling code. Because encapsulation is a usual technique for information hiding, the concepts get blurred.

One should also be aware, when reading about information hiding and encapsulation, that different folks have different definitions. For example, some folks take my definition of information hiding above, and refer to it as encapsulation. I do not like this confusion much, and will summarize my preferred definitions with the following observations:

Encapsulation: data, and the operations on that data, belong in the same class. It stands to reason that a sane design has determined what data belongs together, otherwise all bets are off. Determine the class invariants, and ensure that no use of constructors or methods can violate those invariants.

Information Hiding: deny direct access to data members; use accessors. Hide internal structure of a class, and do not expose implementation details. Expose an interface that represents a conceptual abstraction, and keep the implementation private.

Encapsulation and Information Hiding: a design consideration that is relevant to both concepts - when defining the operations on class data, decide what actions objects of that class must perform, and what information they are required to share.

Encapsulation makes information hiding easier to do. We want both, but they are different concepts. I have found that it makes my life easier when I consider the two ideas separately, and don't lump them in under the one or the other term. YMMV.

No comments:

Post a Comment