Good OO design doesn’t need setters/getters

Migrated from Posterous.
———————————

Today I had one of those “a-ha” moments after I stumbled across some blog posts from two years ago that ran a conversation about the value/need of setters and getters in domain design. As you learn OO, most books teach you encapsulation/data hiding in a simplistic way: make all properties private and add setters and getters for them. As it turns out, this is mostly wrong.

First, some theory. In OO, objects communicate using methods(messages), following a noun/verb parallel. The methods are what the objects do (their external interface), while their properties (private variables) store internal state. (I like to think about objects as finite state machines) As a consequence, when providing setters and getters we are actually reaching deep inside the gut of the object and provide access to its inner workings, thus breaking its encapsulation.

One example of a resulting problem is this: should we ever decide to change the signature or semantics of a property, we’ll have to update all of the clients that use that property (via the getter). As an example, compare the following two class definitions:

class LeakyCustomer {
   private $name; // eg. "John"
   private $surname; // eg. "Doe"
   [...]
   public function getName(){
     return $this->name;
   }
   public function setName($name){
     $this->name = $name;
   }
   public function getSurname(){
     return $this->name;
   }
   public function setSurname($name){
     $this->name = $name;
   }
}

and

class StrongCustomer {
   private $name;
   private $surname;
   [...]
   public function getFullName {
     return $this->name . ' ' . $this->surname;
   }
 }

The first class design implicitly invites its clients to use something like:

$name = $customer->getName().' '.$customer->getSurname();

while the second can only be used as:

$name = $customer->getFullName();

The benefit is obvious if later on the requirements change and we have to accomodate a name prefix such as “Mrs.” or “Mr.”. All clients of LeakyCustomer will have to change

$name = $customer->getPrefix().' '.$customer->getName().' '.$customer->getSurname();

while clients of StrongCustomer will remain unchanged. This is true encapsulation!

There are some caveats though, such as deciding what to do when doing ORM mapping or rendering views (which need access to an object’s state). Suggestions include adding a Composite DisplayableCustomer class, but (sadly), as always, the answer is “It depends”.

For a more in-depth look, take a look at:

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s