Understanding Abstraction in C#

In Object-Oriented Programming (OOP), abstraction is one of three fundamental principles (along with encapsulation and inheritance) that defines the paradigm. Through the use of abstraction, you can hide the unwanted details of the underlying data about an object in order to reduce complexity and increase efficiency (in some cases, which I will mention later). If you have some background in the art, you will realize that it works in the same way. For instance, if you are sketching an apple, it is not desirable to sketch the unwanted details around the apple; the details of an apple is the only thing that really matters to you. In this way, an object that is created through a class represents the original, without unwanted details. You can refer the resulting object itself as an abstraction, i.e., a named entity that is made up of selected attributes and behavior that is specific to a particular usage of the originating entity.

Abstraction is related to both encapsulation and data hiding. Through this design, you can separate interface from implementation. It is often considered the most useful technique in data hiding. It is not only useful in the program for which the design is originally implemented, but in other programs too; if you are creating some library that is going to be used by other programmers, then it is a very useful design for an API (Application Programming Interface) as it completely hides the implementation from a programmer. The users of your library won’t be distracted with the details of methods that does the magic; they would simply use them in the way how you like them to be used

In this tutorial, I will make you understand the concepts of Abstraction and how this design can be implemented in your C# programs. Even though the source code examples that I will provide may be valid for Java (or C++) too, I’m just focusing on C#. So, let’s get started!

Interfaces On The Rescue

Suppose you want to create some graphics library whose purpose is to simply draw a circle or a rectangle to a window. When designing the API with this design in mind, our concern is not how the methods should be implemented, but how a programmer is supposed to use it. Through interface, you can separate the common methods of different classes; this assures that any class that inherits from the given interface must implement the methods defined in the interface else the compiler will give you the errors. Let’s consider an interface “Drawable” with a method “Draw” that needs to implemented in the classes that inherits this interface.

Now, every class that inherit from “Drawable” must implement “Draw”.

In this case, a programmer do not need to worry about the implementation of “Draw”  in every class that implements the interface “Drawable”, they just use those methods in the way they are supposed to be used without worrying about the implementation of different “Draw” methods. Here, you also try to ensure that the entity is named in a manner (“Drawable” in this case should have an obvious “Draw” method) that makes sense and it has all the relevant aspects.

As abstraction provides a programmer a generalized view of the classes, a user of your library can easily examine the interface without reading the implementation, thus it enhances readability. Recall that I have mentioned that abstractness can increase the efficiency in some cases. To unpack what I said: Suppose you have several methods that have similar functionality of “Draw”, but you name them differently, let’s say “Draw” and “DrawOnce”, for drawing in a loop or drawing once respectively. Now the programmer can easily see how those methods are supposed to be used. Conversely, if you use a boolean member in a class, let’s call it “drawOnce”, to flag whether the method “Draw” should draw in a loop or draw once, there is a chance that a programmer will miss the detail and end up using “Draw” without flag of “drawOnce” set to “true” when he/she only wants to draw once, thus the resulting program will not be very efficient.

At this point, I should add that interfaces are linked with the concept of Polymorphism in a sense that it is considered the application of interfaces.

Understanding Polymorphism

Through Polymorphism, a programmer can use the derived class in the place of a base class. It is a way to generically use common methods. Polymorphism can be considered the applications of several concepts such as inheritance, generics etc. I won’t go into the details of Polymorphism and its every possible application. I will focus only on its application of abstraction.

In our example, any class can be passed to a method “Draw” of an instance of “Window” that implements the interface “Drawable”, resulting in expressive code and reduced complexity.

Now, a programmer who likes to draw different shapes other than rectangle and circle can create their own user-defined classes that inherit from “Drawable” and then simply implement the “Draw” method. In this way, the instance of a user-defined class can easily be passed into the method “Draw” of an instance of “Window”. Through the process, we obtained what we wanted in the first place, i.e., data hiding, thus we can conclude that abstraction is indeed a great design for libraries.

Conclusion

In this tutorial, I have showed you the concepts of Abstraction, how it is normally understood in the OOP, and how you can use its amazing power to harness your program. If you have any questions, then you can ask in the comments section below!

CategoriesC#

Leave a Reply

Your email address will not be published. Required fields are marked *