Proper Type Encapsulation - Part One

Encapsulation is the first pillar of Object Oriented Programming and maybe the most important. This is how wikipedia.org defines encapsulation:

Encapsulation is one of the fundamentals of OOP (object-oriented programming). It refers to the bundling of data with the methods that operate on that data. Encapsulation is used to hide the values or state of a structured data object inside a class, preventing unauthorized parties' direct access to them. Publicly accessible methods are generally provided in the class (so-called getters and setters) to access the values, and other client classes call these methods to retrieve and modify the values within the object.

Since I have become a full-time contractor, I rarely see even senior developers get encapsulation right. I would easily say that over 90% of the code I analyze does not follow proper encapsulation rules. If encapsulation isn’t done right then the code isn’t following proper OOP. In most of my conference sessions, I state that if proper OOP isn’t done right then the code will become a house of cards, and all house of cards will fall.

My Mantra

For many years speaking at conferences I have shared my mantra about encapsulation which is bad data in, bad data out! If you let invalid data into your type, then it can cause issues. It’s even worse when this data gets into the database because then it’s very difficult to fix.

Validation

The first rule of encapsulation is, validate all data coming into your type. First, never expose fields, EVER! Fields cannot be validated when being set, so they break encapsulation. All data must be set or retrieved via properties or methods. This way, the data can be validated, events are raised etc. Here is an example of my open source code,

  1. public void Add(T item) {  
  2.     if (item == null) {  
  3.         throw new ArgumentNullException(nameof(item), "Value cannot be null.");  
  4.     }  
  5.     var hashCode = item.GetHashCode();  
  6.     lock(this._lock) {  
  7.         if (this._hashCodes.Contains(hashCode) == false) {  
  8.             base.Add(item);  
  9.             this._hashCodes.Add(hashCode);  
  10.         }  
  11.     }  
  12. }  

As you can see, the first line of code in this method is making sure that item is not null. Then I throw the proper exception ArgumentNullException. The first line of all properties and methods in your type should look like this. Here is an example of validating data being set via a property,

  1. public Int32 Timeout {  
  2.     get {  
  3.         return this._mailServer.Timeout;  
  4.     }  
  5.     set {  
  6.         if ((value != this.Timeout && value >= 0)) {  
  7.             this._mailServer.Timeout = value;  
  8.         }  
  9.     }  
  10. }  

Here I’m making sure the same value isn’t being sent to the property and then making sure the value is equal to or greater than 0. I’m not throwing an exception because, with this validation, the value for Timeout will always be correct since the default value for Int32 is 0.

Making Validation Easier

Recently I wrote an article titled “Make Encapsulation Easy With dotNetTips.Utility” that makes validation easier using my open source code. Using TryValidateParam in the first code example above would look like this:

  1. public new void Add(T item) {  
  2.     Encapsulation.TryValidateParam < ArgumentNullException > (item != null, nameof(item));  
  3.     var hashCode = item.GetHashCode();  
  4.     lock(this._lock) {  
  5.         if (this._hashCodes.Contains(hashCode) == false) {  
  6.             base.Add(item);  
  7.             this._hashCodes.Add(hashCode);  
  8.         }  
  9.     }  
  10. }  

TryValidateParam works from any bool statement and is overloaded to properly validate 12 different types. I hope you will check it out.

Stay tuned for part 2 of this article.


Similar Articles
McCarter Consulting
Software architecture, code & app performance, code quality, Microsoft .NET & mentoring. Available!