Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / polymorphism

The Four Pillars of Object Oriented Design

4.58/5 (15 votes)
26 Nov 2015CPOL8 min read 43.9K  
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 in each of them one by one.

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.

first

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.

second (2)

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. 

third (2)

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.

third (1) (2)

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 strings, 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.

third (3)

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)