Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin and Object Oriented Programming

Kotlin and Object Oriented Programming

A talk given at Gett regarding OOP in Kotlin with respects to the SOLID principles of design

Dor Samet

July 18, 2017
Tweet

More Decks by Dor Samet

Other Decks in Technology

Transcript

  1. What is Object Oriented Programming (OOP)? • A programming paradigm

    ◦ “Everything is an object” • Smalltalk (around 1970) • “Real-World” modeling and programming • Introduces ◦ Abstraction ◦ Encapsulation ◦ Inheritance ◦ Polymorphism
  2. Why OOP • It’s well known and accepted • Allows

    for state organization • Flow of control through interfaces and abstractions
  3. Flow Of Control Main Function High-Level Modules High-Level Modules Low-Level

    Modules Low-Level Modules Low-Level Modules Low-Level Modules
  4. Main Function High-Level Modules High-Level Modules Low-Level Modules Low-Level Modules

    Low-Level Modules Low-Level Modules Flow Of Control With Abstractions High-Level Interface High-Level Interface Low-Level Interface Low-Level Interface Low-Level Interface Low-Level Interface
  5. 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
  6. 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
  7. 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 }
  8. 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 (:)
  9. 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" }
  10. 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" }
  11. Kotlin and OOP - Not So Basic • Data Classes

    • Sealed Classes • Smart Casting
  12. 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!
  13. 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) }
  14. 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)
  15. 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}" } }
  16. SOLID Principles SRP - Single Responsibility Principle OCP - Open/Closed

    Principle LSP - Liskov Substitution Principle ISP - Interface Segregation Principle DIP - Dependency Inversion Principle
  17. 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
  18. 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
  19. 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<String>)" }
  20. Open/Closed Principle Example fun main(args: Array<String>) { val developerA =

    JavaDeveloper() val developerB = KotlinDeveloper() developerA.writeCode() // “public static void main(String[] args)” developerB.writeCode() // “fun main(args: Array<String>)” }
  21. 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
  22. Type Inference - Revisited fun main(args: Array<String>) { val developerA

    = JavaDeveloper() // JavaDeveloper -> Developer val developerB = KotlinDeveloper() // KotlinDeveloper -> Developer developerA.writeCode() developerB.writeCode() } Can we do better?
  23. Liskov Substitution Principle Example fun generateDeveloper(language: String): Developer = when(language)

    { "Java" -> JavaDeveloper() "Kotlin" -> KotlinDeveloper() else -> Developer(language) } fun doWork(developer: Developer) { developer.writeCode() }
  24. 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
  25. Interface Segregation Principle Example interface JavaProgrammer { fun writeJavaCode(): String

    } interface KotlinProgrammer { fun writeKotlinCode(): String }
  26. 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)" }
  27. 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<String>)" }
  28. Interface Segregation Principle Example class KotlinDeveloper: Developer("Kotlin"), KotlinProgrammer { override

    val version: String = "1.1" override fun writeKotlinCode(): String = "fun main(args: Array<String>)" }