Table of Content
- What is Encapsulation?
- What is Information Hiding?
- What is the Difference Between Encapsulation and Information Hiding
- Code Example of the Difference Between Encapsulation and Information Hiding in OOP
- Wrap Off
As a programmer, you may have encountered the words encapsulation and information hiding.
These two concepts are pretty common in Object-Oriented Programming (OOP) especially when we are working with one or more classes.
In this post, you will learn about what they are in programming, why encapsulation is not the same as information hiding, and how we can use it to improve your design system when coding.
What is Encapsulation?
There are two ways to define encapsulation in object-oriented programming.
First Meaning of Encapsulation in OOP
The first definition is the grouping of a concept in a way that each group represents the essential features of another concept.
For example, a document showing the culture of a company encapsulates a company's missions, visions, values, and practices.
Example of Encapsulation in Object-Oriented Programming (OOP)
In object-oriented programming, we can have a Customer
class that represents all the data that we consider to be essential for representing a customer.
Let's look at an example here using python:
The example above is a very simple Customer
class.
Now, there is no way you would at the moment say that this encapsulates what a customer represents.
It has an id, a name, and an email address field.
You might want to add lots of different fields to this customer class.
For example, we want to know the zip code, city, and country as well.
You can add as many fields as possible until you reach a point where this list is going to be complete.
It is going to encapsulate everything that you want a customer to represent.
Second Meaning of Encapsulation in OOP
The second meaning of encapsulation is that it defines boundaries around things.
For example, putting animals in cages in a zoo or being kept behind prison bars for a crime you committed means you have been encapsulated by the government.
So, encapsulation in this sense is about restricting access to some things in one form or the other.
In OOP, you can implement this by making instance variables and methods to be private or protected.
This is well described in programming languages like C++ and Java.
However, the Python programming language is a bit special in handling this situation.
This is because Python does not explicitly allow you to restrict access.
Although, conventionally, most Python developers like myself, use a single underscore to conceptually indicate that a method or function is protected while double underscores represent private.
Second Example of Encapsulation in Object-Oriented Programming (OOP)
For example:
What is Information Hiding?
Information Hiding in OOP means that you keep certain aspects of your code from the outside.
It serves as a kind of black box that other functions, modules, and classes use without having to know anything in particular about how it works internally.
Access to it is usually provided through an interface or API.
Information hiding is similar to encapsulation, but it is not the same thing.
Example of Information Hiding
For example, assuming you create a software that uses a payment system like Plaid or Stripe to process payment at various places in your code, but you don't want that code to be dependent on the payment system itself.
So what do you do?
You hide the information by creating a payment processing module that contains functions for starting a payment, processing refunds, calculating tax percentages, etc.
Inside the module, you can also have the implementation details such as, choosing stripe-specific API calls to make, authenticating the stripe interface, extracting the data and transforming it into a format that your application can use, and so on.
All the other parts of your code will use the stripe payment processing module that you have built.
However, they do not need to know anything about the implementation details that information is hiding.
In that sense, the stripe payment processor module acts as a facade, like a facade design pattern, which is one of the design patterns in the gang of four books.
Example of Information Hiding in Object-Oriented Programming (OOP)
Let's look at another example of implementation hiding in OOP using Python.
Here is an ordering example for an eCommerce:
There are a couple of classes in this file.
We have a PaymentStatus
class which is an Enum
, so it's either canceled, pending, or paid.
There is a StatusError
, which inherits an Exception
class to create a custom exception class.
And we have an OrderItem
class that represents a single order with a name, a price, and a quantity. This class also has a property to compute the total price.
Then we have the Order
class, which has a list of the items to be ordered.
It also has a _payment_status
variable that maintains the current status of the payment of this particular order and a bunch of methods to do something with the order.
The code above is an example where we are applying encapsulation in that we are providing a boundary using the _payment_status
variable, which is marked as a protected variable.
We could also make it private by adding two underscores in front of it __payment_status
.
Since we are using Python, this means that in principle, you are not supposed to use this outside of the Order
class or any class that inherits from the Order
class — even though you can.
We also implement information hiding about what a payment status is.
If you look at the methods, we have is_paid()
, is_cancelled()
, cancel()
, and pay()
, the methods do not get any parameters.
They just return a boolean or null.
So, when you use the Order
class in Python, in principle, you do not need to know anything about how payment status is implemented.
Let's say we wanted to change the _payment_status
variable to an integer value or a string.
We would, of course, have to adapt the bodies of each of the methods, but the user of the Order
class would not have to know anything about that.
Well, unless they were accessing this variable directly, which they're not supposed to because it's conceptually protected, but not inaccessible in Python.
In languages like Java and C++, accessing a protected or private method or variable directly will throw an exception.
So, this encapsulation has a boundary, which is what you see here.
It is a protected member and there is information hiding because the user of the Order
class does not need to know anything about how a payment status in the order is represented.
Example of Information Hiding in methods
Information hiding in object-oriented programming does not always have to be applied to instant variables of classes.
It can be a lot of things such as methods. Take a look at the code below.
For example, here is the previous Customer
class we used earlier slightly adapted to accommodate a protected method.
What we want to achieve here is, if we create a new customer in the system, that customer should automatically receive a welcome email.
However, at the moment, this function does nothing but print the email to the screen.
To do that, we have added a method _send_welcome_email()
that defines a subject, a body, and then calls a send_email()
function.
Notice that the _send_welcome_email()
method itself is protected because we are not supposed to call it explicitly when using the Customer
class.
We added a __post_init__()
dunder method, which calls the _send_welcome_email()
method that in turn sends the welcome emails, after the Object has been initialized, and these values have been set.
So, this example shows how to implement information hiding in OOP using Python.
But, in this case, we are hiding a method, not an instance variable.
What is the Difference Between Encapsulation and Information Hiding
In a simple definition, encapsulation and information hiding help increase cohesion and reduce coupling.
Encapsulation provides boundaries and groups things together. It is very closely related to cohesion. By grouping more things and providing clear boundaries, you are increasing the cohesion of your software.
Information hiding, on the other hand, helps to reduce coupling. It removes dependencies by introducing abstraction layers between the different parts of your code.
Despite their differences, what is fascinating is how encapsulation and information hiding relates to software design principles.
Code Example of the Difference Between Encapsulation and Information Hiding in OOP
Let us look at one more example to show the difference between encapsulation and information hiding.
Here, we have a modified version of the eCommerce store ordering system.
So we have the PaymentStatus
and PaymentStatusError
classes.
No Encapsulation and No Information Hiding Example
The first class after that is an order class called OrderNoEncapsulationNoInformationHiding
class that has no encapsulation or information hiding.
This is the most basic case.
We simply have an instance variable called payment_status
of type PaymentStatus
, that has an initial value of pending.
Anybody who uses this class can access the payment status directly and modify it without any issue, and there is also nothing in the class that indicates that you should not do this.
There are no boundaries whatsoever, so information is not hidden, you can easily access it and there are no indications that you should not.
Encapsulation Without Information Hiding Example
Then, we have another order class called OrderEncapsulationNoInformationHiding
.
This order class is different from the one above because it does have encapsulation.
The instance variable _payment_status
is now a protected instance variable.
We also have two methods: get_payment_status()
and set_payment_status()
in this class.
The internal representation of the payment status, which is an Enum
, is the same as how we are reading and modifying it from the outside.
So there is no information hiding in this case.
If we want to throw away the payment status Enum
, it means you have to change the internal representation.
And we are going to have to change the methods as well because they also rely on payment status.
Information Hiding Without Encapsulation Example
This is another class called the OrderInformationHidingWithoutEncapsulation
Here, we have an order class with information hiding and no encapsulation.
So, the instance variable payment_status
with type Any
and a value of None
is public again, hence, there is no boundary.
We have the medthids is_paid()
, is_cancelled()
, cancel()
, and pay()
here that use the payment status Enum
.
By looking at the class definition or by using the class, we have no idea what payment status is.
There is no boundary. But the information about what it is about and how it is represented is not available to us.
Encapsulation and Information Hiding Example
Here's the fourth class called OrderEncapsulationAndInformationHiding
, which we have seen before.
We have the _payment_status
instance variable, which is encapsulated right. It's a protected member variable and the information about the payment status is internally hidden by the methods is_paid()
, is_cancelled()
, cancel()
, and pay()
.
Since we do not use the payment status Enum
here, that information is hidden.
It also means that if we decide to change the payment status to something else like a string, if we are using this class from the outside, we do not have to change anything.
We simply keep calling these methods, but internally we need to change the code in this class to no longer use the enum.
But, from the outside, nothing is going to change.
Wrap Off
Now, we have seen the difference between encapsulation and implementation hiding in four variants.
We have no encapsulation with no information hiding, encapsulation with no information hiding, information hiding with no encapsulation, and finally, we have encapsulation and information hiding.
The code example on Implementation Hiding without Encapsulation is purely theoretical.
I would never advise you to write classes like that.
Anyway. I hope you enjoyed this post. If you do, consider sharing, and exploring other articles on software design and development.