Part 3 — Abstraction/Encapsulation

Abstraction/Encapsulation

Abstraction and encapsulation are two poles of the same phenomenon. In the OOP approach, abstraction is the delineation of certain interfaces, consistent and complete, for fully working with a class. Here we consider interfaces to mean some public members. Encapsulation, on the other hand, refers to the hiding of data and methods from external consumers, which are necessary for the consistent operation of classes. Encapsulated data or methods should never be used from the outside, to not disrupt the consistency of the class or provide an inconsistent result. The interfaces for working with a class can be considered as a product, delivered to the programmer, conditionally “to protect the program from programmers”. Hiding techniques provide these possibilities.

The abstraction for a class conceptually does not require the use of either interfaces or abstract classes. However, to decompose the abstraction itself and its implementation, in C#, we will have to use interfaces or abstract classes.

When we talk about interfaces and abstract classes — we decompose the abstraction from potential implementations.

Interfaces

Interfaces are convenient in that they avoid cluttering methods within a class with numerous comments on what parameters mean and what can be expected from the method. An interface implies adherence to the Liskov substitution principle, that is, it is undesirable for a class to implement side effects that logically contradict the abstraction, as a distinguished entity. For example, implementations of members of IEnumerable/IList should not send emails or write to the database. It is implied that this is an interface only for enumerating the collection encapsulated in the class.

Regarding C# language tools, an interface may contain:

  • Method signatures
  • Property signatures with access modifiers for getters and setters
  • Event signatures
  • Indexer signature
  • Default method implementations

A class can implement multiple interfaces, thereby narrowing the contract of working with the class depending on the context. Also, interfaces can inherit from interfaces, which is convenient for building chains of interfaces that complement each other. I have already written before about choosing an interface to pass a collection as a parameter. The essence of the article is to show how to correctly use abstraction in your code, depending on your goals.

From a practical application perspective, interfaces bring the most benefit for increasing the interchangeability of classes in an application. When registering classes in an IoC container, it is quite simple to change the implementation that is tied to the interface in a certain scope. This is necessary so that the same code can work with a different set of classes, registered at the start of the application, or so that it is possible to unit-test the code, replacing interfaces with mocks and stubs.

Abstract Classes

One of the goals of abstract classes is to create a single abstraction for a hierarchy, with the ability to define basic behavior that can rely on abstract methods. If interfaces serve more for the extraction of abstraction into a separate entity for the purpose of decomposition and increasing the flexibility of the application, then the goal of an abstract class is to create some kind of basic behavioral code that cannot be discarded by descendants.

In contrast to abstraction, there is the principle of encapsulation. In C#, fields are responsible for this, hence we can’t define a field in an interface, but I don’t quite understand the point of public fields (C# allows it). By default, without an access modifier, fields are private and accessible only from within the class and I believe making fields public violates the principle of abstraction.

Abstraction, or rather its extraction and detachment from implementation, as an element of OOP — is a glue that connects elements of the system, creating a constructor from our application, making the implementation easily replaceable.

--

--