Contribution 50

From WikiContent

Revision as of 13:14, 12 June 2008 by Elandre (Talk | contribs)
(diff) ←Older revision | Current revision (diff) | Newer revision→ (diff)
Jump to: navigation, search

Never ever break the encapsulation

In systems theory containment is one of the most useful constructs when dealing with large and complex system structures. In the software industry the value of containment or encapsulation is well understood, and its supported by programming language constructs such as subroutine, function, module, package, object (class).

Module and package addresses the larger scale needs for encapsulation, while object, subroutine and function addresses the more fine granular aspects of the matter. Over the years I have discovered that objects seams to be one of the hardest encapsulation constructs for developers to get right. It's not seldom you find a class with one single 3000 line main method, or a class with only set and get methods for its primitive attributes. These examples illustrates basically that the developers involved has never understood object oriented thinking, and the power of objects as modeling constructs.

An object encapsulates both state and behavior, where the behavior is defined by the actual state. Think of the object door, it has four states: closed, open, closing, opening. It provide two operations: open and close. Dependent of state the open and close operations will behave differently. This inherent property of an object makes the design process conceptual simple. It boils down to two simple tasks: allocation and delegation of responsibility to the different objects including the inter-object interaction protocols.

How this works in practice is best illustrated by an example. Lets say we have three objects, customer, order and item. The customer object is the natural placeholder of the credit limit and credit validation rules. The order object knows about its associated customer, and its addItem(item) operation delegates the actual credit check by calling customer.validateCredit(item.price()). If the post condition for the method fails, an exception is thrown and the purchase is aborted. This approach of organizing your code is in line with the principles of the Domain Model pattern described by Martin Fowler in his book Patterns of Enterprise Application Architecture [PEAA].

A less experienced object oriented developer might decide to wrap all the business rules into an object very often referred to as order-manager or order-service. In these designs order, customer and item are treated as records and all logic is factored out of the objects and tied together in one single method. These designs are in line with the Transactional script pattern [PEAA], a pattern I found more as an anti-pattern than a pattern for developers working in object oriented programming languages. The reason: It breaks the encapsulation and results in non maintainable code. To illustrate the problem lets extend our small system with more functionality. Customers are classified as gold, silver and basic members, and different discounts are given on that basis. Extend the discount rules to include family size, hair color, car make. Think then about what happens with the maintainability of your code. What initially started out as a 50 line script method has become 2000 lines inter tangled unmaintainable code.

Following the Domain Model approach, extending the customer object with a discount() method while maintaining a consistent allocation of responsibility would have made things simple. With the new method in place the order objects close() method could have obtained the correct discount without knowing anything about membership levels and other discount rules encapsulated by the customer object.

So in the end, never break the encapsulation, and use the power of your favorite object oriented language to maintain it.

By Einar Landre

This work is licensed under a Creative Commons Attribution 3

Back to 97 Things Every Software Architect Should Know home page

Personal tools