You must be thinking that it’s just another whole bunch of crap about a programming paradigm that has been debated, confused and corrected right from the time when it came into existence. But I am quite confident that I’ll not confuse you. I’ll try to be as simple as possible. We are programmers. We learn, we teach, we correct each other. That’s the way it is and that’s the way it actually works. So there are 4 fundamentals ideas of Object Oriented Programming. They have the wonderful terms:
- Abstraction
- Polymorphism
- Inheritance
- Encapsulation
One way to remember these is the acronym APIE. Let’s dive into each of them one by one.
Note – It’s a language agnostic tutorial. I’ll be rather using UML diagrams.
Abstraction
Think of the example of a table. Here, I didn’t say whether it’s a wooden table or a glass top table, if it has four legs or one central pillar, if it’s larger or smaller. You might have an image in mind but that’s okay. I don’t have to get back to the specifics because you understand the idea of a table, the abstraction of the table you’ve seen and experienced enough real tables to abstract the idea what a table means. Abstraction means we have to focus on the essential qualities of something rather than one specific example. It means we automatically will discard what’s unimportant or irrelevant. It’s at the heart of object oriented programming because it’s what we are doing when we make a class. Abstraction means that we don’t create one class for Robert’s bank account and separate class for Julia’s bank account. Instead, we will write one BankAccount
class.
We’ll focus on things like each of these will have an account number
. Each of these will have a balance
. And because we always want to discard what’s unimportant, it’s never just what is a BankAccount
class look like, it’s what should a BankAccount
class look like for this application under these circumstances at this time focusing always just on the essentials. It might be true that every bank account was opened on a specific date but if our application doesn’t care about that piece of information, we don’t need to define that attribute in our class but as we’ll see, it’s abstraction that is the foundation that supports other fundamentals of object orientation such as inheritance and polymorphism.
Encapsulation
Next is the idea of encapsulation. Think something like a space capsule or a medication capsule or even a food container. It’s the idea of surrounding something. Not just to keep the contents together but also to protect them. In object orientation, this refers to the idea of taking our attributes and our behaviors together and bundling them together in the same unit, in the same class. But, it’s really more than that. We also want to restrict access to the inner working of that class or any object based on that class and this is referred to as information hiding. The principal is that the object should not reveal anything about itself except what is absolute necessary for others parts of application to work.
Let me give you an example. Suppose we have the above BankAccount
class, well we don’t want some other part of our application to be able to reach in and change the balance of any object without going through the deposit or the withdrawal behaviors. Perhaps those behaviors are supposed to perform auditing and logging of deposits and withdrawals. So, we can hide that attribute, that piece of data, we can control access to it so that it can only be accessed from inside the object itself. Sure, we can use the deposit
and withdrawals
methods from other parts of the application and they can change the balance but it can’t be changed directly from outside the object. This is also referred to the idea of black boxing. We are closing off more and more of the inner workings of an object except for those few pieces we decided to make public. A common question from folks new to object oriented programming is that if I’m writing these classes, why would I want to hide my own code from myself. Hers’s the thing. It’s not about being secretive. That’s not our point. It’s about reducing dependencies between different parts of our application that a change in one place won’t cascade down and require multiple changes elsewhere. But how much should you hide. What the rule is as much as possible. Different languages have different levels of support for this concept but the idea is that you encapsulate your object’s attributes and methods and then you hide everything about that object except what is absolutely necessary to expose.
Inheritance
The idea of inheritance is first a great form of code reuse. We can create a new class but instead of writing it from scratch, we can base it on an existing class. So, let's you start off by defining in your application a Person
class as shown below.
Then, later on, you figure out your application will need another class and this one called Customer
but you realize that this customer
class is exactly the same as the person
class and the only difference is it also has a customer number
. Now, you don’t want to add that customer number
to your person
class because we’re trying to use abstraction, we’re trying to only focus on essentials and not all of you person objects will be your customer
. You could do this by creating a completely different class but in object orientation a better way is that we will create a new class called Customer
that inherits from Person
class. The phrase we use is Customer
inherits from Person
.
That means our new customer
class automatically has everything that the Person
class has, all its attributes, all its behaviors without us having to write any code. When we just say in our customer
class, what we want to add to it. In this case, we add a customer number
or another new attribute or another add a new method. Now the term that is most commonly used for this relationship is that the Person
class is the superclass and the Customer
class is the subclass. We can also hear this described as the parent class and the child class. Now, not only that but we are not just limited to one of these. We could then create another new class Employee
that also inherit from Person
class so that the Employee
class will have everything the Person
class had but it might add say an employeeId
or payGrade
and perhaps some different behavior. Now the great thing is that if I make a change in the Person
class, it will automatically filter down and affect the two subclasses. One of the best things about inheritance is not just the time you save and being able to reuse code but what it allows us to use the last of our 4 key terms, polymorphism.
Polymorphism
Finally, we have polymorphism which means “many forms”. It’s the most complex of the four terms but very powerful. It lets us automatically do the correct behavior even if what we’re working with could take one of many different forms. Sounds little vague? So, here’s an example of polymorphism that you’ve probably used without even thinking about it. The + sign. Well, what does it do? In a lot of languages it depends. If we are adding two integer variables with the + sign, it will numerically add them. But on the other hand, if the two variables are string
s, it will concatenate them. It’ll automatically do the correct behavior but a different behavior when what we’ve given it could have one of many different forms. Now, this example is built into a lot of languages but we can use the same idea with our own classes, with our own objects. So, here’s an example. If I define a BankAccount
class for our financial application as shown below.
We can then create more specialized subclasses that can inherit from it like a SavingsAccount
class, a CheckingAccount
class, an InvestmentAccount
class so they all inheriting, they all share the basic definition. So, they’ll have an accountName
, a balance
, they can withdraw, they can deposit but the SavingsAccount
might add an interestRate
, an attribute that a CheckingAccount
does not have but then it gets little more complex. Say the business rule says that if you withdraw from an InvestmentAccount,
well you should get a penalty if it not 30 days notice. So, it’s a bit more complex behavior. Now, that withdraw behavior was originally defined in the BankAccount
class that I’m already inheriting but I can provide a more specialized version of that just for the InvestmentAccount
class and this is referred to as overriding the method of the superclass.That just means I write it again. So, I’m inheriting what’s useful but I can override behaviors when that’s useful. Polymorphism lets us work freely with objects that have been created from any of these classes so I can have an array of accounts that have 10000 of these different objects loaded into it and I know that I can call the withdraw()
method on any of them without knowing exactly what class it was instantiated from and it would do the correct behavior for each one just as using the + sign would automatically switch between addition and concatenation. So it’s flexibility. Polymorphism lets us do the right thing at the right time.
That’s my 1614 words about the 4 building blocks of object oriented design. Hope you’ll like it. Please write comments if you want to add or correct something.
The post The Four Pillars of Object Oriented Design appeared first on THELEANCODER.