Explain Encapsulation and Polymorphism Like I'm Five

I had trouble with the concept of "Encapsulation" and "Polymorphism" when I was learning Python a few years ago. I believe I saw a version of that with Java as well (public vs private functions?)

I need an example of how it is used and when I would use it.

Did you find this post useful? Show some love!
DISCUSSION (27)

Polymorphism

ELI 5 example.

Bob is 5 year old Joey's uncle.

Whenever Bob comes over, Joey crawls onto Bob's lap, and Bob greets with "Hey Joey, my angel".

It's X-mas Eve. Uncle Bob visits Joey as Santa 🎅.

Our cute little Joey wears a blissful smile 😄 and jumps onto Santa's lap.

"Ho ho ho, Merry X-mas Joey" greets Santa.

Santa is Bob (Santa inherits from Bob) but Santa greets differently (overriding behavior) when he's Santa Clause.

when I would use it

When you want to optionally handle differently in child classes.

how it is used

Suppose that your site needs to process two payments transaction actions, both of which derive from the same parent and knows how to "processPayment".

  1. PayPal
  2. Credit Card

When your payment processor calls processPayment,

PayPal action will know how to contact PayPal and retrieve money,

and Credit Card action will know how to request Credit Card company for credits.


Encapsulation

ELI 5 example.

Our Joey requested his mom for some pancakes 🥞.

As Joey's served, he asks his Mom how she cooked it 🤔.

Mom placed her index finger on her lips and told him, "Shhh, it's a secret "😉.

Joey got what he what he asked for (pancakes, the public data)

but Mom didn't reveal her recipe and prep steps (internal details).

when I would use it

When you want to hide how your internal state/process is managed.

how it is used

Suppose that your custom NPM library exposes a method to sort an array.

You didn't have time so you used the easiest sorting algorithm (Bubble Sort 😲).

Later on, people reported that it was too slow so you implemented it with a quicksort.

If you have not exposed any logic on how the sorting is implemented,

library users wouldn't have to change their code.

Okay I am a bit confused between Encapsulation and Abstraction. I thought Abstraction was about hiding implementation and Encapsulation was about hiding data. I would appreciate it if you could explain Abstraction as well :D

In a very general sense, all code is abstraction :)

What people mean when they talk about Abstraction is really about turning some code into a more generalized concept. Usually this goes hand in hand with encapsulation, but the two aren't the same and they can be used separately.

If we think about what the word Abstract means, it means "apart from concrete existence". Which is a fancy way of saying it's about describing a real thing in your own words, to make thinking about that real thing easier.

If you're writing some code and you feel like it gets too much to keep track of you might think to yourself "I will make a function to gather up these lines". So you turn your four or five lines of code into a function called user_login() and call it instead of writing those five lines out. user_login() is now an abstraction, instead of the concrete (the five lines you need to execute to login a user) you wrote the abstract concept user_login().

You made up your own word to describe the real thing.

It's not about hiding implementation (anyone can go look at user_login() after all), but about simplifying and generalizing the code in front of you.

Encapsulation is only if you want or not expose something. It could be only one thing no matters what it do. For example: you have a class to calculate a salary with two methods: GetMonthlyWage() and GetWeeklyWage(). Inside the first one you only call GetWeeklyWage() and multiply by 4. Every one could call the first method, then it's public. But you decide if you want the others could see and call GetWeeklyWage() or not. If not, you make it private. The abstraction could use encapsulation, but it is about how a method can be implemented. An abstract class is a template and each implementation of the class (concrete class) could implementate a different way to do something. No matters if it is public or private (or other access modifyer). Then, for contractor employees you could implementate the GetMonthlyWage() giving a bonus and for external workers you could implementate GetMonthlyWage() without the bonus.

I am confused about the difference.

I will do some research and get back later 😎

Abstraction:

Joey's Mom: "Joey, what do you want for breakfast?"
Joey: "I dunno, Mommy... I feel like something sweet and crunchy."
(Abstract class SweetAndCrunchy)

Joey's Mom: "Do you want granola with maple syrup?"
(GranolaMapleSyrup implements SweetAndCrunchy)

-- Edit --

As Dinesh Patra noticed, technically, this should be either:
(Abstract class SweetAndCrunchy)
(GranolaMapleSyrup extends SweetAndCrunchy)

or:

(Interface SweetAndCrunchy)
(GranolaMapleSyrup implements SweetAndCrunchy)

I would like to focus here on the Interface version.
"Abstraction" is a concept. The concept of abstraction in OOP is accomplished at several levels. The topmost level of abstraction is the Interface. An Interface declares one or more methods that should be implemented by the classes that implement that interface.
The next level of abstraction is the Abstract Class. This type of class can't be instantiated: it has to be extended by a concrete (normal) class. The problem with using abstract classes in the current discussion is that an abstract class can in fact already provide an implementation, which makes matters all the more confusing for people trying to learn OOP, so here I would like to stick to the concept of abstraction and forget about specifics.

Thanks Carlos. But I got a doubt.
As per my understanding, We can implement on interface and inherit from abstract classes right. So SweetAndCrunchy is an interface not abstract class.
Please correct me if my understanding is wrong.

Yes, you are right: the "implements" implies SweetAndCrunchy is an Interface.
But we were talking about the concept of abstraction, versus the concept of encapsulation.
"Abstraction" means you are talking about the idea of a thing, and not the concrete thing itself. "Encapsulation" means you can't change the inner workings of the thing.

Abstraction is accomplished at several levels. An Interface is the most abstract level of abstraction there is. To keep it simple, I wouldn't go now into abstract classes because those have very specific technicalities.

Thank you for the clarity explanation.

I like this. You win. 🎉🎉🎉

Thank you for providing an opportunity for let me mull over this 😎.

I love answering these threads so much. It usually forces me to google those last few things on a topic I never really understood.

Yes, and also able to find gaps in our knowledge.

My gap -> Abstraction vs Encapsulation.

Okay I am a bit confused between Encapsulation and Abstraction. I thought Abstraction was about hiding implementation and Encapsulation was about hiding data. I would appreciate it if you could explain Abstraction as well :D

And wonderfully, answered

Encapsulation is only if you want or not expose something. It could be only one thing no matters what it do. For example: you have a class to calculate a salary with two methods: GetMonthlyWage() and GetWeeklyWage(). Inside the first one you only call GetWeeklyWage() and multiply by 4. Every one could call the first method, then it's public. But you decide if you want the others could see and call GetWeeklyWage() or not. If not, you make it private. The abstraction could use encapsulation, but it is about how a method can be implemented. An abstract class is a template and each implementation of the class (concrete class) could implementate a different way to do something. No matters if it is public or private (or other access modifyer). Then, for contractor employees you could implementate the GetMonthlyWage() giving a bonus and for external workers you could implementate GetMonthlyWage() without the bonus.

Polymorphism: You have a tool, all it does is peel fruit, no matter what kind of fruit. So when someone hands you a fruit basket, you don't sweat it, you know you can peel it all.

Contrast that with a citrus juicer, if some one hands you a basket of apples, you can't figure out how to use them with the juicer.

So polymorphism is a way to write code concerning a parent class, and any class that inherits from that parent class is valid input for that piece of code. The "standard" example is that an array of Animal objects- whether it's Dogs, Cats, Birds, whatever- can all call some Animal.speak() function. Each specific animal class implements this different and we get a variety of output.


Encapsulation: You need me to run to the grocery store for you every week. All you do is hand me your credit card, your grocery list, and your car keys and I go. Then after some time, I come back with everything you ask for. You don't know how I get there, what I do on the way, etc. You just know that when you give me the list, money, and keys, I turn it into groceries somehow.

Encapsulation is just the idea that no one outside of the programmer needs to know how parts of objects work. There is a certain part they can see and use, but that's it. So if the implementation changes because the original programmer modified something, the user of their code doesn't have their code suddenly not work.

People relate to you based on what‘s observable: how you look, and how you communicate and behave. That is publicly visible. But what you really think, and your inner workings are a secret. It‘s private.
It‘s encapsulated.

Objects in object oriented programming languages keep secrets as well. The main reason: other objects should not care about their inner workings (i.e. the implementation details), they should only care about their public behavior.

Because if these other objects only care about the public behavior (i.e. they only call the public methods), the implementation details can be changed without affecting the other objects. And that’s really good.

Let’s say I am the public sort method of a sorter object. Somebody hands me a collection of things, I sort them by age and return them. The process of determining the age is really complicated and slow, I need to call a lot of my other methods. All of these methods are private, it’s none of your business how I get things sorted.

Then one day, I discover that the creation date is printed on each of the things you pass to me. Cool! Calculating the age now involves calling fewer methods than before (and they are all private).

The other objects will only notice that I can sort now a lot faster. But as they do not depend on my inner workings, their code doesn’t have to change. They still pass in the exact same collection to be sorted, and get it back sorted.

The compiler makes sure that nobody from the outside can call my private methods.
That‘s encapsulation.

Encapsulation:

Joey's Mom is making lunch: a bit of meatloaf, with mashed potatoes, peas and a couple of carrot slices.

/* @author Mom */
public class Lunch {
    public var pieces = Array;
    private var nutrients = 0;

    public function __construct(todaysLunchPieces) {
        this.pieces = ArrayCopy(todaysLunchPieces);
        this.nutrients = CalculateNutrients(todaysLunchPieces);
    }

    public function eat() {
        return nutrients;
    }

    public function toString() {
        return this.pieces;
    }
...

}

JoeysLunch = new Lunch(['meatloaf', 'mashed potatoes', 'carrots', 'peas']);

Joey asks what's for lunch. Mom answers "Meatloaf, mashed potatoes, carrots, peas". Joey doesn't like peas. He starts picking them and surreptitiously giving them to the dog under the table.

/* @author Joey */
print(JoeysLunch);
JoeysLunch.pieces = ['meatloaf', 'mashed potatoes', 'carrots'];
myNutrients += JoeysLunch.eat();
...

Joey's Mom sees Joey's lunch hack, and says:
"OK, Joey... you don't have to eat the peas, if you don't want to. Gimme your plate."

Next day... Joey's Mom takes all the peas, carrots and leftover mashed potatoes, and grinds them into a nutritious and healthy soup...
Joey's Mom as refactored Lunch:

/* @author Mom */
public class Lunch {
    private var pieces = Array;
    private var nutrients = 0;
    private var description = '';

    public function __construct(todaysLunchPieces, description) {
        this.pieces = ArrayCopy(todaysLunchPieces);
        this.nutrients = CalculateNutrients(todaysLunchPieces);
        this.description = description;
    }

    public function eat() {
        return nutrients;
    }

    public function toString() {
        return this.description;
    }
...

}

JoeysLunch = new Lunch(['meatloaf', 'mashed potatoes', 'carrots', 'peas'], 'Soup');

Now Joey can't change the internal state of his Lunch.
He is only allowed to eat() and only has access to the output of eat() and to a general description of what Lunch is. He can't remove the peas from the soup because the peas are now encapsulated.

Object-Oriented Programming

Encapsulation (the good parts) basically means don't share your private data. That way no one can depend on it, and you can change it (structurally or literally mutating a value) without breaking anyone using your object. 99% of what you should expose on an object is "behavior" aka methods. That way the user of the object focuses on what behavior they want to utilize, not the details of the data. Exceptions being, of course, DTOs which are objects used purely for data purposes. These are used a lot at the edge of systems, because bits going over the wire or being rendered to a monitor, are only data anyway.

Polymorphism is simply substituting one object for another. For example, a car can have a key or push-button start. They work inherently differently, but you could substitute one for the other. Note that since you mentioned Python -- a dynamic language -- you probably don't have to worry about polymorphism too much in practice. It is understood that a variable could be any object. If I call .foo() on the object then I am obviously expecting that method to be there no matter which specific type of object I was given. Static typed languages require extra syntax to handle polymorphism, which could be one of the reasons it is extra emphasized.

Functional Programming

Encapsulation is not so common in FP, since you are encouraged to separate data and functions (into types and modules respectively). Types are primarily used as a means of communication between functions, so they usually don't make sense as private things. And you also don't have to worry about the data you communicated out to another function being changed out from under you, due to immutability. So there's not much need to make data private or encapsulate it behind an object with methods. The FP languages I use do allow for private data, but I rarely bother.

FP does make extensive use of polymorphism, especially for core types like List and the functions on them. So you can make a list of Widget or a list of FooBar. List provides the same functionality no matter which type it is containing. So you can also use the filter function on a list of Widgets or a list of FooBar. In addition to collections, FP typically has some other polymorphic types like Result and Maybe to represent data which can be in an either/or state.

Encapsulation and Polymorphism are often talked about together, but in reality they have very little or nothing to do together. They are both foundational principles of Object-Oriented Programming, but that's about all they have in common, so let's break each one down individually, as understood by a five-year-old.

Encapsulation

This is exactly what is sounds like: encapsulating your stuff so that no one else can see it or touch it without your explicit approval.

As a five-year-old, you have just started kindergarten, and one of the best times of the day is lunch time, of course! You, like many of the other kids in your classroom, brought your lunch with you in your favorite lunchbox. As you place your lunchbox on the shelf with all the others, you just can't help but wonder what lunches some of the other students brought. You see lots of colorful lunchboxes, a few brown paper bags, and even just a plain-old grocery bag, but you can't see inside any of them, so you have no way of knowing what anyone else brought for lunch without going and asking them directly.

And while this can be annoying at times, having to talk to everyone to know what they brought, it is a very good thing that your lunches are all wrapped up nicely. It means that the bullies can't just come and mess with your lunch without you knowing about it. You saw your mom pack your lunch, you know everything that is inside your lunchbox, so it is pretty obvious is anyone else has taken anything, and you can go tell the teacher if you notice anything missing.

Polymorphism

This one is a bit harder to understand as a five-year-old, but the basic idea is that you can build complex "types" out of smaller, simpler "types", or that there can be multiple types that can do similar things. A "type" is just an abstract concept of some "thing", and is usually represented as an encapsulated Object. The object has some internal properties to it, and a public interface that allows access to that data, and that interface can be shared by many different "things".

Going back to the example above, lets say that one day the cafeteria is serving pizza, but a boy in your class can't eat cheese, and so he starts looking to trade lunches. So he starts talking to all the boys and girls that brought their lunch to see if any one of them wants to make a deal. He knows that both the food served in the cafeteria and the lunches in all the lunch bags are edible, but that one of these lunches will probably be better for him than the others. In this situation, the public interface is the fact that he can eat a given lunch, but there are many different types of lunches that could be eaten. The pizza in the cafeteria is a very different lunch than the PB&J sitting in your lunchbox, but because they are both lunches, they can both be consumed in similar ways.

Another way to look at this is through polymorphic inheritance. You know what a sandwich is, and you know that your PB&J is a specific type of sandwich. Anything that any other sandwich can do can also be done by your PB&J, namely holding stuff between 2 pieces of bread, it just happens that your specific type of sandwich holds peanut butter and jelly between its slices.

Encapsulation?! Encapsulation is when you need to mess with something but at the same time need to protect yourself (or protect this thing) while you mess with it!

Like change the car direction... to turn the car direction you need to turn the wheels to the direction you want. But you don't stop the car and turn the wheels using your hands! To this purpose you use the car steering wheel. The car steering wheel will talk to the wheels to change the direction!

Polymorphism?! Humm... go ask you mom!

Encapsulation is related to the visibility of properties/methods. Basically, if you have a sensitive property (for example, an 'age' property that should not be lower than 18) which you do not wish to be explicitly changed, then you declare it as private and provide getters and setters in which you can make sure that your rule (age > 18) is respected.

Polymorphism means "multiple shapes". This comes handy when you have a functionality, such as sending notifications to users, that might have several forms, such as sending an email notification or an SMS notification. You must make sure that you are "programming to an interface, not to an implementation". This means that your notification sending mechanism should refer to the interface that is implemented by both of your email and SMS sending notification classes. So you are depending of the interface that has MANY forms (email and SMS), making your code both clean and flexible.

[deleted]

Be careful, what you are describing is not polymorphism!

You an Animal class with children classes Herbivore and Carnivore for example. Then each child implements its own overriden version of function feed ().
For herbivores:
-find herb
-eat herb

For carnivores:
-find prey
-hunt prey
-eat

Even when the implementation is different for each kind of animal, you know that for any animal you can call the function feed for it and it will have the right behavior, this is Polymorphism.

Now imagine you have two pokemons in the pension and one day you come and the okd lady says "Your pokemons came back wih an egg, we don't know where they found it but here it is". So you got a behavior: receive an egg. But there is some internal hidden behavior : You don't know where it comes from. You know what happens but not how. This is encapsulation; you have access to some interface function but not access to the parameters it plays with

Encapsulation and polymorphism are general object oriented programming concepts, together with abstraction and inheritance, they form four pillars of OOP.

The encapsulation is hiding the details of "how the thing is working" and shows only single/few buttons to press to "make the thing working". (Stepping out of the ELI5 mode: These may be implemented via private/public or via interface and interface implementation, public API calls, etc.)

Polymorphism allows to modify class behavior based on the data type you provide. If you imagine an oven, it allows to bake a cake, roast veggies, roast nuts, grill tofu. You use it a bit different depending on what type of food you input to it. The same concept exists in the OOP world:

void PlaySound (AmbientSound snd)
{
dimm_the_lights();
set_volume(LOW);
play(snd)
}

void PlaySound (AlertSound snd)
{
turn_on_alert_lights();
set_volume(MAX);
play(snd);
}

Further reading: beginnersbook.com/2013/03/oops-in-...

Encapsulation: You can drive a car, but don't need to know how the engine works.
Polymorphism: Brother and sister are two different people but have the same parents.

I did a 90 second video on polymorphism which explains s it pretty well I think:
youtu.be/Y_q3TRgeUnY

Classic DEV Post from Sep 15

Implement a serverless CI/CD pipeline with AWS (Amazon Web Services).

This article series focused on implementing a serverless CI/CD with AWS services, During the implementation process we are going introduce lots of new AWS services.

Cat Carbonell
Product Designer, attempting front-end development figuring out how to bridge the communication gap between designers and engineers
Join dev.to ❤️

The heartbeat of the software industry.