Encapsulation using primary / secondary constructors

Encapsulation in Kotlin involves restricting direct access to class variables and exposing them through controlled methods (getters and setters). In Kotlin, you can achieve encapsulation seamlessly using properties with custom accessors or by controlling the visibility of variables.

Here’s how to add encapsulation to class variables when using primary or secondary constructors:


1. Encapsulation with Primary Constructor

The primary constructor can automatically define and initialize class properties with encapsulation using visibility modifiers (private, protected, etc.) and custom getters/setters.

Example:

class Person(private var _name: String, private var _age: Int) {
// Public getter for name
var name: String
get() = _name
set(value) {
if (value.isNotBlank()) _name = value
}

// Public getter and setter for age with validation
var age: Int
get() = _age
set(value) {
if (value > 0) _age = value
}

init {
println("Person created with Name: $_name, Age: $_age")
}
}

// Usage
val person = Person("Alice", 25)
println(person.name) // Accessing name
person.name = "Bob" // Changing name
person.age = -5 // Invalid age; won't update
println("Updated Name: ${person.name}, Age: ${person.age}")

Explanation:

  • _name and _age are private and cannot be accessed directly outside the class.
  • name and age are public properties with controlled access.
  • Validation logic ensures only valid values are set.

2. Encapsulation with Secondary Constructor

For secondary constructors, you can initialize private variables and expose them through public properties.

Example:

class Car {
private var _brand: String = ""
private var _speed: Int = 0

// Secondary constructor
constructor(brand: String, speed: Int) {
if (brand.isNotBlank()) _brand = brand
if (speed > 0) _speed = speed
}

// Public getter and setter for brand
var brand: String
get() = _brand
set(value) {
if (value.isNotBlank()) _brand = value
}

// Public getter and setter for speed with validation
var speed: Int
get() = _speed
set(value) {
if (value > 0) _speed = value
}
}

// Usage
val car = Car("Toyota", 120)
println("Brand: ${car.brand}, Speed: ${car.speed}")

car.speed = 150 // Updates speed
car.brand = "" // Invalid; won't update
println("Updated Brand: ${car.brand}, Speed: ${car.speed}")

Explanation:

  • _brand and _speed are private variables initialized in the secondary constructor.
  • brand and speed are public properties with controlled access.

3. Encapsulation with private set

Kotlin allows you to make the setter of a property private while keeping the getter public. This ensures that the property can only be modified within the class.

Example:

class BankAccount(val accountNumber: String, initialBalance: Double) {
private var _balance: Double = initialBalance

// Public read-only property
val balance: Double
get() = _balance

// Public method to update balance
fun deposit(amount: Double) {
if (amount > 0) _balance += amount
}
}

// Usage
val account = BankAccount("12345", 1000.0)
println("Account Balance: ${account.balance}")

account.deposit(500.0) // Update balance through deposit method
println("Updated Balance: ${account.balance}")

Explanation:

  • balance is read-only outside the class but can be updated internally through the deposit() method.

4. Encapsulation Using Visibility Modifiers

Kotlin offers these visibility modifiers:

  • private: Accessible only within the class.
  • protected: Accessible within the class and its subclasses.
  • internal: Accessible within the same module.
  • public: Accessible from anywhere.

Example:

class Employee(private val id: Int, private var salary: Double) {
fun showDetails() {
println("Employee ID: $id, Salary: $salary")
}

fun updateSalary(newSalary: Double) {
if (newSalary > 0) {
salary = newSalary
}
}
}

// Usage
val emp = Employee(101, 50000.0)
emp.showDetails()
// emp.id or emp.salary cannot be accessed directly

Best Practices

  1. Use private variables to restrict direct access to sensitive data.
  2. Expose data using custom getters and setters to validate or control access.
  3. Use read-only properties (val) for values that shouldn’t change after initialization.
  4. Combine encapsulation with Kotlin’s visibility modifiers for better control.

😊

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *