
To get started, there’s nothing better than talking about the concept that emerged as the only common ground of the committee of wise men mentioned in the previous post: encapsulation. Then we’ll talk about visibility, a concept that usually goes hand in hand with encapsulation, to the point of being treated as the same thing. To finish, we’ll spend a few lines on state retention, something very obvious but essential in object-oriented programming.
Encapsulation
Encapsulation lets us group functionality (methods) and state (data) in a cohesive way. The methods provide the right mechanisms to modify the state and, in some cases, they are also the way to access it.
That’s it, you don’t need much more fuss to describe what encapsulation is. In fact, we could even define it as “keeping the data and the functionality directly related to it all snug together, and drawing a perimeter we give a name to”, but the definition would look uglier ;)
In languages like Java, the way to access the state is through getXXX() methods. In C# we have properties, so we can use them to access the state. Even so, sometimes it will also be convenient to use methods to access the state.
Visibility
When we talk about visibility we usually mean hiding or publishing both the state information and the implementation of a class’s functionality.
Visibility lets us hide from the outside details of the state or the implementation that we don’t want exposed outside our “unit of encapsulation”
A very simple example: in a game we don’t want anyone to know the characters’ health, we only want them to know whether the character is alive, wounded or dead. We could use a private property that stores the character’s hit points and a public method that gives us its status. The method would calculate the status from the player’s hit points, but the hit points would never be exposed.
The concept of visibility tends to go along with encapsulation, to the point that encapsulation and visibility are sometimes assumed to be synonyms. Quite a few books have described it that way. But the word “encapsulation” is used with different meanings: in some cases it’s used to talk about visibility, and in others it refers exclusively to the definitions I use in this post. I debated this topic quite a bit with Fran Reyes back in the day and his point of view convinced me.
The purpose of encapsulation is not information hiding.
Languages like Python provide encapsulation through classes, but the concept of private visibility is essentially a convention.
State retention
In functional programming, every time we call a function we have to give it the data it has to work with, and it in turn returns the data with the relevant changes applied. As Javier Neira rightly corrected me, functions can also keep state by using closures.
In object-oriented programming, we don’t have to give our methods the state information they have to work with, since they can access it inside the object. An object keeps its state between calls.
Anemic models
The concept of an anemic model is related to applying object-oriented programming incorrectly. When we have classes that only have properties with public getters and setters, and the code that manages the state lives outside the classes themselves, we have an anemic model.
If we put the state management logic outside the object, we’re not applying encapsulation correctly and therefore we’re not applying object-oriented programming correctly.
A simple example (taken from Wikipedia) would be:
Anemic:
class Box
{
public int Height { get; set; }
public int Width { get; set; }
}
Object-oriented:
class Box
{
public int Height { get; private set; }
public int Width { get; private set; }
public Box(int height, int width)
{
if (height <= 0) {
throw new ArgumentOutOfRangeException(nameof(height));
}
if (width <= 0) {
throw new ArgumentOutOfRangeException(nameof(width));
}
Height = height;
Width = width;
}
}
Properties vs fields in C#
Sometimes there’s the question of whether in C# we should use properties or public fields to expose state. For many developers there isn’t much difference, but we should keep in mind that properties have some distinctive features compared to fields:
- Accessing a property counts as a method call, which means we can change the implementation of both the Get and the Set in the future. This is related to the concept of hiding the implementation, and it isn’t possible with a variable.
- Since accessing a property counts as a method call, we can run code when its value is accessed.
- With properties we can manage the visibility of the get and the set separately.
- Properties can’t be passed by reference to methods.
As for whether to use a property or a method for getters, personally I like to use properties when I access the “raw” state, untreated, and so I’ll get it immediately. I use methods when I’m going to do some transformation or apply some kind of logic, especially if it’s heavy logic. I think it makes it much more explicit that by accessing that data through a method we’re doing an operation that won’t be instantaneous.
Let’s also remember that methods can be made asynchronous, but properties can’t.
As for data collections, we have to think carefully about the kind of collection we’re going to use. If we use collections that aren’t “readonly”, we lose the ability to easily intercept the code that modifies the collection, something very common when we want to apply validations or any other kind of logic. If we expose a collection that isn’t read-only, we’re ruling out encapsulating the management logic of that property.
Another interesting concept related to state retention is immutability, but we’d better leave that for another day ;)
The Yoda drawing comes from the Vecteezy website