Encapsulation is one of the fundamental principles of Object-Oriented Programming (OOP). It refers to the bundling of data (attributes) and methods (functions) that operate on the data into a single unit, typically a class. Encapsulation also involves restricting direct access to some of an object's components, which is a means of preventing unintended interference and misuse of the data.
Key Concepts of Encapsulation
- Data Hiding: Encapsulation allows the internal state of an object to be hidden from the outside. This is typically achieved using access modifiers.
- Access Modifiers: These are keywords used to set the accessibility of classes, methods, and other members. Common access modifiers in Groovy include:
private: The member is accessible only within the class.protected: The member is accessible within the class and by subclasses.public: The member is accessible from any other class.
- Getters and Setters: Methods that provide controlled access to the attributes of a class. Getters retrieve the value of an attribute, while setters modify the value.
Practical Example
Let's create a simple class Person to demonstrate encapsulation in Groovy.
class Person {
private String name
private int age
// Getter for name
String getName() {
return name
}
// Setter for name
void setName(String name) {
this.name = name
}
// Getter for age
int getAge() {
return age
}
// Setter for age
void setAge(int age) {
if (age > 0) {
this.age = age
} else {
println "Age must be positive."
}
}
}
// Using the Person class
def person = new Person()
person.setName("John Doe")
person.setAge(30)
println "Name: ${person.getName()}"
println "Age: ${person.getAge()}"Explanation
- Private Attributes: The
nameandageattributes are declared asprivate, meaning they cannot be accessed directly from outside the class. - Getters and Setters: The
getName,setName,getAge, andsetAgemethods provide controlled access to thenameandageattributes. - Validation: The
setAgemethod includes a validation check to ensure the age is positive.
Practical Exercises
Exercise 1: Create a BankAccount Class
Create a BankAccount class with the following attributes and methods:
private double balancepublic double getBalance()public void deposit(double amount)public void withdraw(double amount)
Ensure that the withdraw method does not allow the balance to go negative.
Solution
class BankAccount {
private double balance = 0.0
double getBalance() {
return balance
}
void deposit(double amount) {
if (amount > 0) {
balance += amount
} else {
println "Deposit amount must be positive."
}
}
void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount
} else {
println "Invalid withdraw amount."
}
}
}
// Using the BankAccount class
def account = new BankAccount()
account.deposit(100.0)
account.withdraw(30.0)
println "Balance: ${account.getBalance()}"Exercise 2: Create a Student Class
Create a Student class with the following attributes and methods:
private String studentIdprivate String nameprivate double gpapublic String getStudentId()public void setStudentId(String studentId)public String getName()public void setName(String name)public double getGpa()public void setGpa(double gpa)
Ensure that the setGpa method only accepts values between 0.0 and 4.0.
Solution
class Student {
private String studentId
private String name
private double gpa
String getStudentId() {
return studentId
}
void setStudentId(String studentId) {
this.studentId = studentId
}
String getName() {
return name
}
void setName(String name) {
this.name = name
}
double getGpa() {
return gpa
}
void setGpa(double gpa) {
if (gpa >= 0.0 && gpa <= 4.0) {
this.gpa = gpa
} else {
println "GPA must be between 0.0 and 4.0."
}
}
}
// Using the Student class
def student = new Student()
student.setStudentId("S12345")
student.setName("Alice")
student.setGpa(3.8)
println "Student ID: ${student.getStudentId()}"
println "Name: ${student.getName()}"
println "GPA: ${student.getGpa()}"Common Mistakes and Tips
- Direct Access: Avoid accessing private attributes directly from outside the class. Always use getters and setters.
- Validation: Always include validation in setters to ensure the integrity of the data.
- Encapsulation Overhead: While encapsulation adds a layer of protection, it can also introduce some overhead. Use it judiciously to balance between protection and performance.
Conclusion
Encapsulation is a powerful concept in OOP that helps in protecting the internal state of an object and provides controlled access to its attributes. By using access modifiers and getter/setter methods, you can ensure that your classes are robust and maintainable. In the next topic, we will explore more advanced OOP concepts such as inheritance.
