In part 1 of this article, I explained how to implement proper data encapsulation. In part 2 I want to talk about encapsulating business logic. I see this missing in a lot of type design, especially when using an ORM like Entity Framework.
It’s the job of the architect and coder of that type to make sure that the business logic is encapsulated in it. This ensures that whoever is using the type does not need to know deep knowledge on how the business logic works. They should just create it and then just call properties and methods. For example, when you call BeginTransaction() from the SqlConnection type, do you know exactly what that method does? Of course not, that was the job of the architect and coder of that method to include that in SqlConnection. If something goes wrong, then an exception will be thrown (hopefully).
In part 1, I discussed how important validating the data coming into the type. As I said, bad data in… bad data out. Some of you might think that code to connect to the database is encapsulation and it is, but below I will be focusing on the logic that usually the architect needs to come up with to make it easier on any developer consuming that type without needing to have domain logic of. I personally try to make sure a developer at any level should be able to quickly understand how to use that type, without reading the documentation.
Encapsulate Creating a Collection
Let’s say you have a type called OrderCollection that contains a collection of Order. By design, there cannot be and orders with a duplicate id’s or maybe even order data? Sure, that can be done by creating proper indexes in the database, and it should. There are two possible issues with this way of thinking.
- Indexes can hurt the performance of the database, especially inserts. They can also take up a lot of room on a disk drive.
- As a developer, I shouldn’t need to look at the documentation or the database to figure out what constitutes a unique order. What if I don’t have access to see that info in the database? The more likely scenario is it isn’t documented. Even if it is, the documentation is likely to be out of date.
What makes a unique order should be encapsulated into the type so all I must do as the consumer of that type is something like this,
- public sealed class OrderCollection: List<Order>
- {
- public static OrderCollection Create(IEnumerable<Order> orders)
- {
- if (orders == null)
- {
- throw new ArgumentNullException(nameof(orders),
- "Orders cannot be null.");
- }
- var ordersAdded = new OrderCollection();
- foreach (var order in orders.Where(o => o != null))
- {
- ordersAdded.Add(order);
- }
- return ordersAdded;
- }

Join the conversation! Your thoughts help the community grow.