- Published on
OOP Mastery: Encapsulation in Kotlin
- Authors
- Name
- Dan Tech
- @dan_0xff
OOP Mastery is a series of self-taught Object-Oriented Programming articles with the Kotlin language, compiled at DanTech0xFF. The purpose of this series is to provide a comprehensive view of Object Orientation in the Kotlin language. This will be a solid foundation for future Programmers if you delve into Android, Mobile Cross Platform, or Backend Java.
- Part 1: OOP Mastery: Class Types, Interface in Kotlin
- Part 2: OOP Mastery: Encapsulation in Kotlin
- Part 3: OOP Mastery: Inheritance in Kotlin
- Part 4: OOP Mastery: Polymorphism in Kotlin
- Part 5: OOP Mastery: Abstraction in Kotlin
In this article, we will analyze the Encapsulation of OOP in the Kotlin programming language.
Recalling Encapsulation
Encapsulation is the ability to control the access level of properties within a Class. This is to ensure the integrity of data and logic of a Class to serve the features of a Library or program.
Access Modifiers in Kotlin
Kotlin provides several types of access modifiers.
When declaring without a specific Access modifier, Kotlin will consider it a public access modifier by default.
class DefineKotlinAccessModifier {
val publicModifier: String = "Public Modifier"
internal val internalModifier: String = "Internal Modifier"
protected val protectedModifier: String = "Protected Modifier"
private val privateModifier: String = "Private Modifier"
}
Kotlin provides programmers with Properties Getter, Setter tools to be more versatile in Encapsulation design.
class EncapsulationKotlin {
var dynamicString: String = "Initialized Value"
private set // limits the scope of the set function, dynamicString can be accessed from the outside, but setting must be done inside the Class
var anotherDynamicString: String = "Another Initialized Value"
set(value) {
field = "Another $value"
} // customize the logic of the set function for anotherDynamicString
}
How to Choose the Appropriate Access Modifier
The general principle in designing a Class is to limit the arbitrary modification of an object's property. This limitation helps to focus the logic of the Class, and only the required behaviors need to be public.
Principle 1: If a variable does not need to be accessed from the outside, use protected or private
class DatabaseService {
var dbName: String = ""
// db logics
}
// This is a bad practice when designing the DatabaseService class.
// The dbName variable for storage is marked as public and mutable -> can be changed at runtime.
// The way to improve is
class DatabaseService(private val dbName: String) {
// Db logics
}
// At this point, the dbName variable stores only one value needed to initialize the database, and cannot be changed over time.
// From the outside, it is not possible to access dbName to control the value of this variable
Principle 2: If a variable needs to be accessed from the outside to read the value, use protected or private for the setter
class DatabaseService(dbName: String) {
var databaseName: String
private set
init {
databaseName = dbName
}
// Db logics
}
Principle 3: If a variable needs to be accessed and set from the outside. Do not set the value directly to the variable, use a setter to control the code better.
class MyWifiController() {
var currentDeviceCount: Int = 0
set(value) {
if (value > maxDeviceCount) {
println("Device count is too high")
return
}
field = value
}
var maxDeviceCount: Int = 10
set(value) {
if (currentDeviceCount > value) {
println("Current device count is greater than max device count")
return
}
field = value
}
}
// An example in the case where the Programmer needs to force the public setter to be exposed