Encapsulation | OOP

Encapsulation is one of the fundamental principles of Object-Oriented Programming (OOP). It involves bundling data (attributes) and methods (functions) that operate on that data into a single unit called a class. The data within a class is typically kept private, and access to it is controlled through public methods, often called getters and setters. This ensures that the internal state of an object is protected and can only be modified in a controlled manner.


Here's an example in C# that demonstrates encapsulation:

    
using System;

public class Person
{
    // Private fields (attributes)
    private string name;
    private int age;

    // Public constructor
    public Person(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    // Public method to get the name (getter)
    public string GetName()
    {
        return name;
    }

    // Public method to set the name (setter)
    public void SetName(string newName)
    {
        name = newName;
    }

    // Public method to get the age (getter)
    public int GetAge()
    {
        return age;
    }

    // Public method to set the age (setter)
    public void SetAge(int newAge)
    {
        if (newAge >= 0) // Ensure age is non-negative
        {
            age = newAge;
        }
        else
        {
            Console.WriteLine("Age cannot be negative.");
        }
    }
}

class Program
{
    static void Main()
    {
        // Create a Person object
        Person person = new Person("Alice", 30);

        // Access and modify properties using getter and setter methods
        Console.WriteLine($"Name: {person.GetName()}, Age: {person.GetAge()}");
        person.SetName("Bob");
        person.SetAge(25);
        Console.WriteLine($"Updated Name: {person.GetName()}, Updated Age: {person.GetAge()}");
    }
}
using System;

public class Person
{
    // Private fields (attributes)
    private string name;
    private int age;

    // Public constructor
    public Person(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    // Public method to get the name (getter)
    public string GetName()
    {
        return name;
    }

    // Public method to set the name (setter)
    public void SetName(string newName)
    {
        name = newName;
    }

    // Public method to get the age (getter)
    public int GetAge()
    {
        return age;
    }

    // Public method to set the age (setter)
    public void SetAge(int newAge)
    {
        if (newAge >= 0) // Ensure age is non-negative
        {
            age = newAge;
        }
        else
        {
            Console.WriteLine("Age cannot be negative.");
        }
    }
}

class Program
{
    static void Main()
    {
        // Create a Person object
        Person person = new Person("Alice", 30);

        // Access and modify properties using getter and setter methods
        Console.WriteLine($"Name: {person.GetName()}, Age: {person.GetAge()}");
        person.SetName("Bob");
        person.SetAge(25);
        Console.WriteLine($"Updated Name: {person.GetName()}, Updated Age: {person.GetAge()}");
    }
}



In this example:



- The `Person` class encapsulates the `name` and `age` fields as private members.


- Public getter (`GetName`, `GetAge`) and setter (`SetName`, `SetAge`) methods are provided to access and modify these private fields.


- The `SetAge` setter includes a check to ensure that the age is non-negative.



This encapsulation ensures that the internal state of a `Person` object is controlled, and external code can interact with it only through defined methods, maintaining data integrity and allowing for validation or additional logic when setting values.


In the example I provided, the concept of "bundling" in encapsulation is represented by the `Person` class itself. The `Person` class bundles both data (attributes) and methods (functions) into a single unit. Let's break down how this bundling occurs:


1. Data (Attributes):

   - The `Person` class contains private fields (attributes) like `name` and `age`. These fields hold the data associated with an individual person.


2. Methods (Functions):

   - The `Person` class defines public methods like `GetName`, `SetName`, `GetAge`, and `SetAge`. These methods operate on the data (attributes) of a `Person` object.


The bundling aspect of encapsulation is that the data (attributes) and the methods that work with that data are encapsulated within the same class. This means that these fields and methods are closely related and are meant to be used together to represent and manipulate the state of a `Person` object.


So, the bundling in encapsulation is achieved through the organization of both data and methods within a single class, providing a clear and controlled interface to interact with the encapsulated data.


Questions related to encapsulation in Object-Oriented Programming (OOP):


1. What is encapsulation, and why is it important in OOP?

   - Encapsulation is the bundling of data (attributes) and methods (functions) that operate on that data into a single unit (a class). It is important because it helps maintain the integrity of data by restricting direct access, allowing controlled modification and validation.


2. How is encapsulation achieved in a class?

   - Encapsulation is achieved by declaring the data members of a class as private (or protected) and providing public methods (getters and setters) to access and modify these data members.


3. What is the purpose of a getter method in encapsulation?

   - A getter method is used to retrieve the value of a private field (attribute). It allows controlled access to the data and ensures that the internal state of an object is not exposed directly.


4. Explain the role of a setter method in encapsulation.

   - A setter method is used to modify the value of a private field (attribute) while enforcing validation rules or constraints. It allows controlled modification of data.


5. Why are data members often marked as private in encapsulation?

   - Data members are marked as private to prevent direct access and modification from outside the class. This helps maintain data integrity and allows for better control over how data is manipulated.


6. Give an example of a situation where encapsulation would be beneficial.

   - Encapsulation is beneficial when dealing with a `BankAccount` class, where the account balance should not be directly accessible or modified by external code. Instead, it should be accessed and modified through methods like `Deposit` and `Withdraw` to ensure accurate and secure transactions.


7. Can encapsulation be achieved without using getter and setter methods?

   - While getter and setter methods are a common way to achieve encapsulation, some languages offer properties or direct field access control mechanisms. However, the principle remains the same: controlling access to data.


8. How does encapsulation promote code maintainability?

   - Encapsulation makes it easier to modify the internal implementation of a class without affecting external code. Changes to the class's data or methods can be managed internally, preserving the external interface.


9. What is the difference between public, private, and protected access modifiers in encapsulation?

   - Public members are accessible from anywhere, private members are only accessible within the class, and protected members are accessible within the class and its derived classes. Encapsulation typically involves private members.


These questions cover the core concepts and benefits of encapsulation in OOP. Understanding encapsulation is essential for writing maintainable and secure object-oriented code.

Coding problem related to encapsulation along with its solution in C#:


Problem: Create a `BankAccount` class that encapsulates the balance of a bank account. Ensure that the balance cannot be accessed or modified directly from outside the class. Implement methods to deposit and withdraw money from the account while applying validation to prevent negative balances.


Solution:

 
    
using System;

public class BankAccount
{
    private decimal balance; // Private field to store the balance

    // Constructor to initialize the balance
    public BankAccount(decimal initialBalance)
    {
        if (initialBalance >= 0)
        {
            balance = initialBalance;
        }
        else
        {
            Console.WriteLine("Initial balance cannot be negative.");
        }
    }


    // Method to deposit money into the account
    public void Deposit(decimal amount)
    {
        if (amount > 0)
        {
            balance += amount;
            Console.WriteLine($"Deposited ${amount}. New balance: ${balance}");
        }
        else
        {
            Console.WriteLine("Deposit amount must be positive.");
        }
    }

    // Method to withdraw money from the account
    public void Withdraw(decimal amount)
    {
        if (amount > 0 && balance >= amount)
        {
            balance -= amount;
            Console.WriteLine($"Withdrawn ${amount}. New balance: ${balance}");
        }

        else if (amount <= 0)
        {
            Console.WriteLine("Withdrawal amount must be positive.");
        }
        else
        {
            Console.WriteLine("Insufficient balance for withdrawal.");
        }
    }

    // Method to check the account balance
    public decimal GetBalance()
    {
        return balance;
    }
}



class Program
{
    static void Main()
    {
        // Create a bank account with an initial balance of $1000
        BankAccount account = new BankAccount(1000);

        // Perform transactions
        account.Deposit(500);
        account.Withdraw(200);
        account.Withdraw(2000); // Should show an insufficient balance message

        // Check the final balance
        decimal finalBalance = account.GetBalance();
        Console.WriteLine($"Final balance: ${finalBalance}");
    }
}


In this solution:


- The `BankAccount` class encapsulates the balance as a private field, ensuring that it cannot be accessed directly from outside the class.

- The constructor initializes the balance, and the `Deposit` and `Withdraw` methods allow for controlled modifications while applying validation.

- The `GetBalance` method is provided to check the balance.


This problem demonstrates how encapsulation helps create a secure and controlled interface to interact with the bank account's balance.

Comments