What are abstract classes?
An “abstract class” is a class that is created with the intention of never being instantiated by an object. Basically this means that the created class will define what properties, methods, and/or events are contained within the class. The methods and/or events may also contain required arguments, as well as expected return data types.
How do you use abstract classes?
We use “abstract classes” through derived classes. Derived classes are the most common type of method used with abstract classes by beginning software developers. This is because they are based on principals that are already learned, and an abstract class can contain both abstract members and non-abstract members. Since the abstract member’s (methods in particular) don’t have implementation code, you may wonder how the derived class would know what to do. This is where polymorphism would come in; you are defining the method at the time you create the derived class, the only thing the “abstract base class” is requiring is that you match all of it’s arguments at minimum and you must use the same data types for the arguments, and if applicable you must use the same data type for the returned values also.
You should be made aware of another way of getting the same result as an abstract class is through an “interface”. Interfaces slightly differ in two ways:
- Interfaces members must all be implemented (there is absolutely no implementation code in an Interface), where as an abstract class could hold both abstract methods and methods that can be used by the base class, and
- a derived class can use as many Interfaces as the developer wishes, where as only one abstract class can be used inherited (there are ways around this by creating derived abstract classes of the base abstract class, and then chaining down the abstract classes until all are included and then creating a final derived class to be used – I.E. abstract 1 into abstract 2 into abstract 3 into abstract 4 into derived class 1; thus creating a derived class containing all 4 abstracts).
All of this may seem difficult to understand at first, especially the ‘why would you want to use abstract classes over interfaces’, this will be discussed in a future blog. For now, I’ll concentrate on solidifying the concept and use of an abstract class.
First, I’ll try to give you a better real-world relation to what an abstract class is. I will use an example of abstract art to relate this (you may have heard of this term previously, although not in programming classes or discussions, and you may have even seen this type of art before). Imagine a professor of an advanced art class sets an apple on the table and tells his class he wants an abstract of the apple, and he specifies they must use their own method of creating this art; they are not allowed to use any methods taught within that particular art class. One artist (we’ll call him Artist A) creates an painting of the art using oil-based paints, another artist (Artist B) creates a clay model of the apple, and yet another artist (Artist C) creates a photograph of the apple. Now imagine the same professor in a beginner’s art class and shows them a red rubber ball; he tells them they can only recreate the art using a pencil and paper. So each artist returns with a very basic black, gray and white drawing of the ball.
The reason I use this example is because the professor is a real-world example of an abstract class; he had given a definition to his advanced class of what he wanted (recreation of the apple), and he specified they were to create their own methods. The method was chosen by each artist (painting, pottery, and photography). In his beginner’s class he had specified 1 method that must be used (to recreate the ball). All of these artists would be considered our derived classes. The professor would be an “abstract base class” because he had forced 1 class to create their own method; but also remember that he also had the ability to force 1 class to use a specific method! (NOTE: This will become an important point in understanding differences between “abstract” and “interfaces”)
Now, I’ll give you a real-world programming example of how you would use an abstract class. Imagine you are creating an application that records the results of all examinations performed by any doctor on any patient. We would want to use an abstract class in the records class because we do not have the specific information as to what the exam is, who the patient is, what the results of the exam are, or the comments left by the doctor. In particular our record will need to hold all this information. We obviously don’t want to create a very large block of code to handle all possibilities. First problem we will face is that we don’t know what exams there are or if there are any special requirements of information (from the doctor or the patient) to complete this exam. An example of special requirements is that a patient who has a physical would need to have their age, height, weight and such recorded; where a patient having a follow-up visit for a broken arm may only need their age recorded. Another example would be a patient receiving a pregnancy exam may need to have their expected due date recorded.
A good solution to this is to create an abstract base class that would hold common information for all patients, regardless of exam being used. Since this class is simply just a template of the patients information we need to record we will not want to allow any implementations of the information for two specific reasons, 1) we don’t want to create duplication of information between classes (this allows for easier code maintainability later), and 2) we want to force our derived classes to determine how they want to use the information (we only want to ensure they include this basic information, they can determine if additional information is required).
So, we know that every patient has the property of: first name, last name, and age. We also know that every patient will have a method of: exam results, and doctor’s comments. We would then create the base class using they keyword abstract. We will define any properties and methods as public within this class that the derived class can use; remember we are not telling the derived class how to implement the public properties and methods, we are only telling the derived class that it must implement them (we don’t care how).
You will see in this block of coding I had created a class called “base_patient”. This is our abstract base class:
using System; |
Now that we have our abstract class, let’s look at an example of where a derived class will use the abstract class. Let’s implement a derived class that is just for a general check-up for all patients; in particular it will consist of: a blood pressure test, exam results and tonsil examination (if patient still has tonsils). Notice the last examination is based on if the patient still has their tonsils; but, you may have also noticed that our abstract class doesn’t contain this information! Remember, we are using a derived class, so we can create a new property in this derived class to hold that information, and since we are implementing our own method, we can determine if we want anything specific to happen if the patient does or doesn’t have tonsils.
Here is the coding to create the general check-up class, named, “general_checkup”:
using System; |
Now that we have a derived class, we can then use this class within our program to display the information of the patient and the results of the exam. Remember all information is stored within an object instance of the derived class,”general_checkup”, because the base class, “base_patient” is an abstract class and cannot be instantiated.
Here is the coding to create the basic program file called “program.cs”:
using System; |
As you can see from the above coding examples the abstract class can come in handy for determining what properties, methods (including arguments and return values, if we want), and events will be used in the derived class.
You will want to use abstract classes to allow your programs to maintain flexibility and help to ensure code quality. By specifying within the abstract class what properties and methods are required you can ensure that all derived classes contain this; should any derived class not contain this information then an error can be generated. For this to occur you only need to use the keyword abstract in the method that must be inherited and overridden.
In this particular instance I had only created one (1) derived class; this is just to shorten the length of the blog; as you may remember from the real-world comparison I had used three artists, and each one had implemented their own methods of creating the end-result. This is the exact same idea behind programming derived classes. In the first derived class we had created an additional property of Boolean type that had stored if the patient had their tonsils or not.
One other thing I had not quite covered is that you can derive a class from a derived class and have the second-generation derived class inherit all of the first-generation’s derived properties, methods and events. You can also create abstract classes that are derived from an abstract class.
An example of where you may want to create a ‘second-generation’ abstract class, based on our “base_patient” abstract class is if you had wanted to have a sub-set of classes for pregnancy related exams. You may have two exams for pregnancy women, one to determine what trimester of pregnancy the patient is in, and one for general follow-up exams during the pregnancy.
As you can imagine these two pregnancy classes could have overlapping properties; thus you may want to create an abstract class containing general pregnancy properties and methods. Such properties you may want to contain in the abstract class would be the conception date and patients weight (as you can tell, I had omitted this property from the abstract base class for demonstration reasons in this paragraph). You may also want to define methods within this ‘second-generation’ abstract class, such as: a calculation of due date.
Once you have this ‘second-generation’ abstract class you could then create derived classes that would implement these properties and methods as appropriate for their needs. You will want to test these concepts out on your own, such as take this coding and create an abstract class deriving from the abstract base class, then creating a derived class from the ‘second-generation’ abstract class (an idea would be instead of working with dates, you could have the abstract pregnancy class hold the patients number of conceived days, and then have the method defined to calculate the remaining number of days until expected due date. You could have a derived pregnancy exam implement the calculation using the total_days_within_pregnancy minus conceived days).
One last thing, you may be wondering why I chose to call the base abstract class “base_patient”, as opposed to something like “base_records”. This is to show you how polymorphism kind of plays into the abstract world, although this is not truly polymorphism (for more information about “polymorphism” see my previous blog called, “A brief look at polymorphism and how it is used…”). You can make a fairly decent assumption based on the class name that the original intention of the base class was for creating objects, or in this case derived classes, relating directly to patients. Records are somewhat related to patients; however, they are not a direct link to the patient class. In this instance I am demonstrating how you can take an abstract class and use it in any form of derived class as you wish, as long as you maintain the inheritance rules (for my information about “inheritance” see my previous blog called, “A brief look at inheritance and how to inherit”).
As you can see abstract offers a large amount of flexibility in your programs and should be used when possible or practical. In this example we had simply created a way for you to create a default class for records of exams and made it so you can easily add additional record exam classes as you need them. This has minimized the amount of code required, by eliminating repetitive code such as the patients name and age, and it has also used a method to ensure the proper use of the method by defining the method’s arguments. This will seem like a lot of information to take in at first, after a few trial-and-error runs you will quickly get the hang of how to use abstract classes. If you are still unsure of the benefits of using abstract classes, then try re-creating this code by creating separate classes, then imagine trying to do this with a full-featured application that could have hundreds of properties for the patient, hundreds of methods for exams and thousands of records with different types of information; you will quickly realize the benefits that are gained from this simple concept.
In my next blog I will delve a little deeper into the “abstract” world and start to discuss “abstract methods” and the following blog will be about “interfaces”. These two upcoming blogs will compliment, and build upon, your knowledge of “abstract classes”.
Until then…Happy Coding!