Kotlin and OOP
● Everything is an object
● Primitives are boxed at compile time
● Classes are derived from Any (Or Any?)
● Not covered in this session
○ Nullable classes are derived from Any?
○ Nothing is also something but it’s not Any
○ Generics
Slide 9
Slide 9 text
Kotlin and OOP - Basics
● Classes class Person(val firstName: String, val lastName: String) {
fun fullName(): String = "$firstName $lastName"
}
interface Person {
val age: Int
fun fullName(): String
}
abstract class Person(val firstName: String,
val lastName: String) {
abstract fun fullName(): String
}
● Interfaces
● Abstract Classes
Slide 10
Slide 10 text
Kotlin and OOP - Basics
● Enum Classes enum class Person {
ALEX {
override fun sayName() = "Alex"
},
DOR {
override fun sayName() = "Dor"
},
IGOR {
override fun sayName() = "Igor"
};
abstract fun sayName(): String
}
Slide 11
Slide 11 text
Kotlin and OOP - Inheritance
● A class may only extend one class
● A class may implement many interfaces
● An interface may extend other interfaces
● To do all of this - use a colon (:)
Slide 12
Slide 12 text
Inheritance Example
interface Person {
fun fullName(): String
}
abstract class Bob(open val firstName: String): Person {
abstract fun fullName(): String //can be omitted
fun sayName(): String = "My Name Is $firstName"
}
Slide 13
Slide 13 text
Inheritance Example - Continued
class BobDylan: Bob("Bob") {
override fun fullName(): String = "${sayName()} Dylan"
}
class BobDole(override val firstName: String = "Bob",
val lastName: String = "Dole"): Bob(firstName) {
override fun fullName(): String = "I'm Bob Dole"
}
abstract class Bob(open val firstName: String): Person {
abstract fun fullName(): String //can be omitted (from person)
fun sayName(): String = "My Name Is $firstName"
}
Slide 14
Slide 14 text
Kotlin and OOP - Not So Basic
● Data Classes
● Sealed Classes
● Smart Casting
Slide 15
Slide 15 text
Data Classes
data class Elvis(val firstName: String = "Elvis",
val lastName: String = "Presley")
open data class Elvis(val firstName: String = "Elvis",
val lastName: String = "Presley")
Compiler will
complain!
Slide 16
Slide 16 text
Sealed Classes
sealed class Person(val firstName: String,
val lastName: String) {
class Dor: Person("Dor", "Samet")
class Alex(val age: Int, fName: String, lName: String)
: Person(fName, lName)
}
Slide 17
Slide 17 text
Sealed Classes - Since Kotlin 1.1
sealed class Person(val firstName: String,
val lastName: String)
class Dor: Person("Dor", "Samet")
data class Alex(val age: Int, fName: String, lName: String)
: Person(fName, lName)
Slide 18
Slide 18 text
Smart Casting
fun translatePerson(person: Person): String =
when (person) {
is Person.Dor -> {
"${person.firstName} ${person.lastName}"
}
is Person.Alex -> {
"${person.fName} ${person.lName}, of age
${person.age}"
}
}
SOLID Kotlin Language Features
SRP - Single Responsibility Principle - “by” keyword which will get its own talk
OCP - Open/Closed Principle
LSP - Liskov Substitution Principle
ISP - Interface Segregation Principle
DIP - Dependency Inversion Principle - named and default parameters
Slide 23
Slide 23 text
Open/Closed
Principle
“I am open to extensions and
closed to modifications”
Slide 24
Slide 24 text
Open/Closed
Principle
Open/Override
● Classes are final by default
● Must explicitly write “open” for
extendable classes and
methods
● Must explicitly write “override”
for extending classes and
methods
Slide 25
Slide 25 text
Open/Closed Principle Example
open class Developer(val language: String) {
open fun writeCode() = "I Write code in $language"
}
open class JavaDeveloper(otherLanguage: String) : Developer(otherLanguage) {
open val version = "9"
constructor(): this("Java") //Secondary Constructor
override fun writeCode(): String = writeJavaCode()
protected open fun writeJavaCode() = "public static void main(String[] args)"
}
class KotlinDeveloper: JavaDeveloper("Kotlin") {
override val version: String = "1.1"
override fun writeJavaCode(): String = writeKotlinCode()
private fun writeKotlinCode(): String = "fun main(args: Array)"
}
Slide 26
Slide 26 text
Open/Closed Principle Example
fun main(args: Array) {
val developerA = JavaDeveloper()
val developerB = KotlinDeveloper()
developerA.writeCode() // “public static void main(String[] args)”
developerB.writeCode() // “fun main(args: Array)”
}
Slide 27
Slide 27 text
Liskov
Substitution
Principle
“Replacing me with my parent
should not break the system”
Slide 28
Slide 28 text
Liskov
Substitution
Principle
Type Inference
● Built-in type inference
● Exchanging between items
using type inference is not even
a line
● Sealed classes
● When expressions
● Smart casting
Slide 29
Slide 29 text
Type Inference - Revisited
fun main(args: Array) {
val developerA = JavaDeveloper() // JavaDeveloper -> Developer
val developerB = KotlinDeveloper() // KotlinDeveloper -> Developer
developerA.writeCode()
developerB.writeCode()
}
Can we do better?
Slide 30
Slide 30 text
Liskov Substitution Principle Example
fun generateDeveloper(language: String): Developer =
when(language) {
"Java" -> JavaDeveloper()
"Kotlin" -> KotlinDeveloper()
else -> Developer(language)
}
fun doWork(developer: Developer) {
developer.writeCode()
}
Slide 31
Slide 31 text
Liskov Substitution Principle Example
fun main(args: Array) {
val developer = generateDeveloper("Java")
doWork(developer)
}
Slide 32
Slide 32 text
Liskov Substitution Principle Example
fun main(args: Array) {
val developer = generateDeveloper("Kotlin")
doWork(developer)
}
Slide 33
Slide 33 text
Liskov Substitution Principle Example
fun main(args: Array) {
val developer = generateDeveloper("Python")
doWork(developer)
}
Slide 34
Slide 34 text
Interface
Segregation
Principle
“I should not be forced to
implement methods I do not
need”
Slide 35
Slide 35 text
Interface
Segregation
Principle
Interfaces are basically abstract
classes with all abstract
methods
● A class may implement
multiple interfaces
● Interfaces may have default
implementations of functions
● Interfaces may have members
Slide 36
Slide 36 text
Interface Segregation Principle Example
interface JavaProgrammer {
fun writeJavaCode(): String
}
interface KotlinProgrammer {
fun writeKotlinCode(): String
}
Slide 37
Slide 37 text
Interface Segregation Principle Example
open class JavaDeveloper(otherLanguage: String) :
Developer(otherLanguage), JavaProgrammer {
open val version = "9"
constructor(): this("Java")
override fun writeCode(): String = writeJavaCode()
override fun writeJavaCode() = "public static void main(String[]
args)"
}
Slide 38
Slide 38 text
Interface Segregation Principle Example
class KotlinDeveloper: JavaDeveloper("Kotlin"), KotlinProgrammer {
override val version: String = "1.1"
override fun writeJavaCode(): String = writeKotlinCode()
override fun writeKotlinCode(): String = "fun main(args:
Array)"
}
Slide 39
Slide 39 text
Interface Segregation Principle Example
class KotlinDeveloper: Developer("Kotlin"), KotlinProgrammer {
override val version: String = "1.1"
override fun writeKotlinCode(): String = "fun main(args:
Array)"
}