Encapsulation

Out of Sight!

Feeding Your Monkey

Your Feed method in VirtualPet was an example of encapsulation. It probably resembled this:

public void Feed() {
  Hunger -= 5;
}

So we fed our pets like this:

myMonkey.Feed();

Here, the VirtualPet class is responsible for updating hunger when a pet feeds. A benefit of this is that the VirtualPet class encapsulates the effect of a feeding. In this case, it decreases hunger by five.

If we were to do this in a procedural fashion without encapsulation, we might do this from our Main method in our app:

myMonkey.Hunger -= 5; // feed myMonkey

Hide Your Hunger

An example of violating encapsulation is the way we've handled accessing our VirtualPet's hunger so far. You may have been doing something like this:

Console.WriteLine("My pet's hunger is " + myMonkey.Hunger);

That's all well and good while only our app class is using VirtualPet, but what if other developers start using our code, and someone (let's assume innocently) does something like the following?

thatPet.Hunger = -5;

That would wreck your assumptions about hunger a bit, wouldn't it? We avoid this situation by giving our Hunger instance variable a private accessibility modifier.

public class VirtualPet
{
  public int Hunger { get; private set; }
  // ...
}

How do I get at it?

Once our Hunger setter is now private, meaning Hunger can no longer be set anywhere outside of our class. We can still get the value from outside the class, however:

int petsHunger = myMonkey.Hunger;

Even though we can access Hunger externally, we should usually let our VirtualPet class make any decisions that involve its Hunger.


For example, we may need to figure out if our pet is "Hungry" or not.

public class VirtualPet
{
  public int Hunger { get; set; }
  public bool IsHungry()
  {
    return Hunger > 50;
  }
}

Why is the above code so much better than writing the code below?

static void Main(string[] args)
{
  VirtualPet myPet = new VirtualPet();
  bool isHungry = myMonkey.Hunger > 50;
}

Keep Your Hands to Yourself

Encapsulation is the practice of hiding information about an object from other objects. We do this so that the responsibility for manipulating state is limited to one object.

A classic example of encapsulation is the cashier collecting the price of a purchase. The cashier asks you for money to cover your purchase. You withdraw the money from your wallet/purse/pocket, then he returns your change. The cashier does not reach into your pocket, withdraw your wallet, remove money, then put change into your wallet.

Shotgun surgery, a design smell from Fowler's Refactoring, can be an indicator of poor encapsulation. This analogy references the small pellets resulting from a shotgun blast, the removal of which requires surgery at several places. Poor encapsulation means that a small change can require us to change several classes.


I spy, with my little eye…

Visibility modifiers allow us to specify the visibility of an element (who can see it). From most visible to least visible, these are:

modifier visibility
public everyone can see it
protected this class and subclasses can see it
none (default) things in the same assembly can see it
private only visible inside this class, not even subclasses can see it

The instance variables (fields) that define the state of your objects should have less than public visibility.

In practice, most things will be public or private. Sometimes, you will see protected. You will almost never see default visibility in practice. (There's nothing wrong with default visibility. This is more a statement about practices in the industry and the level of craftsmanship.)


In Practice

In reading your book, it may feel like publicly "settable" properties violate encapsulation. For example, when our monkey's Hunger property was:

public int Hunger {get; set;}
myMonkey.Hunger = 35;

How is this any better than directly manipulating a field:

public int hunger;
myMonkey.hunger = 35; // direct manipulation

The answer is, it's not much better. We could do some validation of the value passed into the setter, but this isn't much different. Setter methods violate encapsulation by definition. We introduce them because you will see them in the wild, where sometimes they are used to do great damage.


In Practice...keep setters private when you can

Luckily, we can usually avoid using public setters. Avoid them when you can.

  • Prefer constructor parameters to initialize state.
  • Use methods to encapsulate interactions with your state.
  • Never make your fields public. At a minimum, wrap them in a property.