Object-Oriented Programming: Encapsulation


Encapsulation is the process of combining data members (fields/properties) and behaviors (methods/functions) into a single unit (class, interface, struct).
Real-world Example
For example, a Bag and its contents. In this illustration, all the contents of the bag, such as books, pens, rulers, etc., are combined and stored in a bag. We cannot take out the pen, book, and various other items inside the bag without first opening the bag.
Code Example
class Bank
{
public long AccountNumber;
public string Name;
public int Balance;
public void GetBalance()
{
}
public void WithdrawAmount()
{
}
public void Deposit()
{
}
}
In the example above, the Bank class is an example of encapsulation. The data members and methods of the class are bound in a single unit, which is the Bank class.
Here, encapsulation binds the implementation details of the Bank class. If there is code that wants to access the fields & methods in the Bank class, it must first initialize an object of the Bank class, as shown in the code below.
Bank bank = new Bank();
// The property and method below cannot be accessed without first
// declaring an object of the bank class.
bank.AccountNumber = 12345678;
bank.Name = "Kristiadhy";
bank.GetBalance();
bank.WithdrawAmount();
Data Hiding in Encapsulation
The biggest advantage of encapsulation is data hiding, the process where we hide internal data from the outside world. Data hiding is also known as Data Encapsulation.
To hide and expose data, we need access modifiers. Access Modifiers are keywords that determine the accessibility level of a class, method, variable, and other members.
In C#, generally, access modifiers can be divided into 4 (although it can be more if combining several access modifiers), for example:
Private.
Members can only be accessed within the class itself.
Protected.
Members can be accessed within the class and all its derived classes.
Internal.
Members can be accessed within the same assembly.
Public.
Members can be accessed by the same assembly or different assemblies that reference it.
Here is the code example:
public class BankDataEncapsulation
{
// The balance field is hidden from access outside the class
// by using the private access modifier
private double balance;
// Create public Setter and Getter methods
// Public Getter method
// This method is used to return the value of the balance variable
public double GetBalance()
{
// We can add validation if necessary
return balance;
}
// Public Setter Method
// This method is used to assign a value to the balance variable
public void SetBalance(double balance)
{
// We can add validation to check
// whether the input data is correct or not.
this.balance = balance;
}
}
In the code example above, in the class, we have a field balance set as private. The field cannot be accessed by anyone outside its class (even if the class has been initialized as an object). An example can be seen in the code below.
BankDataEncapsulation bankEncapsulation = new BankDataEncapsulation();
bankEncapsulation.balance; // This line will result in a compile-time error.
So how do we manipulate the balance value in the BankDataEncapsulation class? We can do it by accessing the getter and setter methods that have been set as public. Please see the code example below.
BankDataEncapsulation bankEncapsulation = new BankDataEncapsulation();
bankEncapsulation.SetBalance(500);
Console.WriteLine(bankEncapsulation.GetBalance());
This way, the balance field is safe and locked so that its value cannot be changed except by the methods allowed by the class through certain access modifiers. This ensures data security.
Additionally, when we want to add validation to the balance value, we can add it by modifying the getter and setter methods, so we don't need to change the code when calling the method. Here is the code example.
public double GetBalance()
{
// In the getter method, we add validation.
if(balance > 1000000)
throw new Exception("Anda tidak bisa cek saldo diatas 1000000");
return balance;
}
public void SetBalance(double balance)
{
// We also add validation in the setter method.
if(balance < 0)
throw new Exception("Saldo tidak boleh negatif");
this.balance = balance;
}
We can see that even though there is additional logic in both methods, the code when calling the method remains the same/unchanged, still like this.
BankDataEncapsulation bankEncapsulation = new BankDataEncapsulation();
bankEncapsulation.SetBalance(500);
Console.WriteLine(bankEncapsulation.GetBalance());
This is very advantageous because we don't need to make many adjustments when there is a change in logic. This is a simple example of the benefits of the Encapsulation concept.
Some Benefits of Encapsulation
Data Protection.
We can validate data before storing it in a variable.
Data Hiding.
The caller will not know about the implementation of the parts inside the class.
Security.
The principle of encapsulation helps secure our code by ensuring that other units (class, interface, etc.) cannot access data directly.
Flexibility.
The principle of encapsulation makes our code more flexible, allowing programmers to easily change or update the code.
Control.
The principle of encapsulation provides greater control over the data stored in variables. For example, we can control data by validating whether it is good enough to be stored in a variable.
We have learned about one of the concepts of the 4 pillars of OOP, which is Encapsulation. Next, we will learn about another concept in OOP, which is Polymorphism.
Subscribe to my newsletter
Read articles from Kristiadhy directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Kristiadhy
Kristiadhy
Experienced Full Stack .NET developer with a proven track record of designing and implementing robust business applications. Proficient in using ASP.NET Core Web API, Blazor, and WinForms to deliver high-quality, efficient code and scalable solutions. Strong focus on implementing industry best practices for cleaner and scalable outcomes.