Saturday, August 17, 2019

Abstract Classes, Interfaces, Inheritance & Type Alias pada Kotlin

Sekarang mari belajar pemrograman berorientasi objek di Kotlin dengan mempelajari abstract classes, interfaces, dan inheritance. dan type aliases. 
Kotlin mendukung abstract classes—seperti di Java, Sebuah abstract class adalah kelas yang tidak utuh atau tidak berguna tanpa adanya sublass yang konkrit (non-abstract) yang bisa dipakai untuk membuat objek. Subclass konkrit dari sebuah abstract class mengimplementasi semua method dan properti yang didefinisikan di dalam abstract class—jika tidak maka subclass itu masih termasuk abstract class!
Membuat sebuah abstract class dengan modifier abstract (mirip seperti Java)
1
2
3
abstract class Employee (val firstName: String, val lastName: String) {
    abstract fun earnings(): Double
}
Perlu dicatat bahwa tidak semua member harus abstract. Dengan kata lain,  juga bisa memberikan implementasi default di dalam sebuah abstract class.
1
2
3
4
5
6
7
abstract class Employee (val firstName: String, val lastName: String) {
    // ...
     
    fun fullName(): String {
        return lastName + " " + firstName;
    }
}
Buat fungsi non-abstract bernama fullName() di dalam sebuah abstract class Employee. Kelas konkrit (subclass dari abstract class) dapat meng-override implementasi default sebuah method abstract—namun hanya jika method tersebut memiliki modifier open 
Juga dapat menyimpan state di dalam abstract classes.
1
2
3
4
abstract class Employee (val firstName: String, val lastName: String) {
    // ...
    val propFoo: String = "bla bla"
}
Meskipun abstract class tidak memiliki method apapun, masih perlu membuat sebuah subclass sebelum kita dapat membuat objek, lihat contoh di bawah.
1
2
3
4
5
6
class Programmer(firstName: String, lastName: String) : Employee(firstName, lastName) {
 
    override fun earnings(): Double {
        // calculate earnings
    }
}
Kelas Programmer kita meng-extends abstract class Employee. Di Kotlin menggunakan karakter titik dua (:) bukannya kata kunci extends yang dipakai Java untuk meng-extends sebuah kelas atau mengimplementasi sebuah interface.
Buat sebuah objek dengan tipe Programmer dan memanggil method-nya di objek tadi—baik method kelas itu sendiri maupun superclass-nya (base class).
1
2
val programmer = Programmer("Chike", "Mgbemena")
println(programmer.fullName()) // "Mgbemena Chike"
Satu kemampuan untuk meng-override sebuah properti val (immutable) dengan var (mutable).
01
02
03
04
05
06
07
08
09
10
11
12
13
14
open class BaseA (open val baseProp: String) {
 
}
 
class DerivedA : BaseA("") {
 
    private var derivedProp: String = ""
 
    override var baseProp: String
        get() = derivedProp
        set(value) {
            derivedProp = value
        }
}
Pastikan penggunaan fungsionalitas ini dengan abik, karna tidak bisa melakukan kebalikannya—meng-override properti sebuah var dengan val.
Sebuah interface secara sederhana adalah koleksi dari method  yang memberitahu objek apa yang harus dapat ia lakukan dan bagaimana melakukannya. (Default method di interface merupakan fitur baru yang ditambahkan ke Java 8.) Dengan kata lain, sebuah interface merupakan kontrak yang harus diimplementasi oleh kelas yang mengimplementasinya. 
Sebuah interface dibuat dengan menggunakan kata kunci interface di Kotlin (mirip dengan Java).
1
2
3
4
5
6
7
class Result
class Student
 
interface StudentRepository {
    fun getById(id: Long): Student
    fun getResultsById(id: Long): List
}
Pada kode di atas, mendeklarasikan sebuah interface StudentRepository. Interface ini memiliki dua method abstract: getById() dan getResultsById(). Perlu dicatat bahwa penggunakan kata kunci abstract di sebuah interface adalah redundan karena mereka secara implisit sudah merupakan sebuah kelas abstract. 
Sebuah interface tidak berguna tanpa sebuah kelas yang mengimplementasinya—jadi sekarang mari kita buah sebuah kelas yang akan mengimplementasi interface ini.
1
2
3
4
5
6
7
8
9
class StudentLocalDataSource : StudentRepository {
    override fun getResults(id: Long): List {
       // do implementation
    }
 
    override fun getById(id: Long): Student {
        // do implementation
    }
}
Di sini dapat dibuat sebuah kelas StudentLocalDataSource yang mengimplement interface StudentRepository
Gunakan modifier override untuk menandai method dan properti yang ingin dibuat ulang dari sebuah interface atau superclass—mirip seperti anotasi @Override di Java.
Ingat aturan-aturan tambahan berikut untuk interface in Kotlin:
  • Sebuah kelas dapat mengimplementasi interface sebanyak-banyaknya, tapi ia hanya bisa meng-extend satu kelas (mirip dengan Java).
  • Modifier override wajib ditambahkan di Kotlin—tidak seperti di Java.
  • Seperti method, juga dapat mendeklarasikan properti di interface Kotlin.
  • Method di interface Kotlin dapat memiliki implementasi bawaan (seperti Java 8).
Mari kita lihat sebuah contoh dari method interface dengan sebuah implementasi bawaan.
1
2
3
4
5
6
interface StudentRepository {
    // ...
    fun delete(student: Student) {
        // do implementation
    }
}
Pada kode di atas, menambahkan sebuah method baru delete() dengan sebuah implementasi bawaan.
dan juga memiliki kebebasan untuk meng-override implementasi bawaan jika mau.
1
2
3
4
5
6
class StudentLocalDataSource : StudentRepository {
    // ...
    override fun delete(student: Student) {
       // do implementation
    }
}
Seperti yang sudah dijelaskan, interface Kotlin dapat memiliki properti—namun catat bahwa ia tidak bisa menyimpan suatu nilai. (Meski begitu, ingat bahwa abstract classes bisa menyimpan nilai.) Jadi pembuatan interface berikut dengan sebuah properti akan bekerja. 
1
2
3
4
interface StudentRepository {
    val propFoo: Boolean // will work
    // ...
}
Namun apabila kita mencoba menambah suatu nilai pada properti tersebut, interface itu tidak akan bekerja.
1
2
3
4
interface StudentRepository {
    val propFoo: Boolean = true // Error: Property initializers are not allowed in interfaces
    // ..
}
Namun, sebuah properti interface di Kotlin dapat memiliki getter and setter. namun properti di dalam sebuah interface tidak dapat memiliki sebuah backing field.
01
02
03
04
05
06
07
08
09
10
interface StudentRepository {
    var propFoo: Boolean
        get() = true
        set(value)  {
           if (value) {
             // do something
           }
        }
    // ...
}
juga dapat meng-override sebuah properti interface jika mau.
01
02
03
04
05
06
07
08
09
10
class StudentLocalDataSource : StudentRepository {
    // ...
    override var propFoo: Boolean
        get() = false
        set(value) {
            if (value) {
                 
            }
        }
}
Mari lihat kasus di mana memiliki sebuah kelas yang mengimplementasi beberapa interface dengan nama method yang sama. Bagaimana kelas tersebut menentukan method milik interface mana yang akan dipanggil?
1
2
3
4
5
6
7
interface InterfaceA {
    fun funD() {}
}
 
interface InterfaceB {
    fun funD() {}
}
Di sini memiliki dua interface yang memiliki sebuah methode dengan nama sama funD(). Mari buat sebuah kelas yang mengimplementasi dua interface ini dan meng-override method funD().
1
2
3
4
5
class classA : InterfaceA, InterfaceB {
    override fun funD() {
        super.funD() // Error: Many supertypes available, please specify the one you mean in angle brackets, e.g. 'super'
    }
}
Kompiler akan bingung saat memanggil super.funD() karena ada dua interface yang diimplementasi di dalam kelas yang sama dan memiliki nama method yang sama.
Untuk menyelesaikan masalah ini, membungkus nama interface yang methodnya ingin panggil ke dalam kurung sudut 
1
2
3
4
5
class classA : InterfaceA, InterfaceB {
    override fun funD() {
        super.funD()
    }
}

3. Pewarisan
Sebuah kelas baru (subclass) dibuat dengan mengambil isi kelas super dan mungkin mendefinisikan ulang implementasi bawaannya.  Mekanisme ini dikenal dengan istilah pewarisan dalam konsep pemrograman berorientasi objek (PBO). 
Base class untuk semua kelas di Kotlin adalah Any.
1
2
class Person : Any {
}
Kelas Any mirip dengan Object yang ada di Java.
1
2
3
4
5
public open class Any {
    public open operator fun equals(other: Any?): Boolean
    public open fun hashCode(): Int
    public open fun toString(): String
}
Kelas Any memiliki beberapa method berikut: equals()hashcode(), dan toString().
Kelas tidak perlu secara eksplisit meng-extend Any. Jika tidak secara eksplisit menentukan sebuah kelas meng-extend kelas apa, maka secara implisit ia akan meng-extend Any. Untuk alasan ini, biasanya tidak perlu menambahkan : Any di kode yang ditulis—kita menulisnya di atas hanya untuk contoh. 
Mari buat kelas-kelas di Kotlin untuk membahas pewarisan. 
1
2
3
4
5
6
7
class Student {
 
}
 
class GraduateStudent : Student() {
 
}
Pada kode di atas kelas GraduateStudent meng-extend superclass Student. Tapi kode ini tidak akan berjalan. Mengapa? Karena kelas dan method bernilai final secara otomatis di Kotlin. Dengan kata lain, secara otomatis tidak bisa di extend—berbeda dengan Java di mana kelas dan method sudah terbuka secara otomatis. 
Para ahli menganjurkan untuk membuat kelas dan method final secara otomati, artinya jika tidak secara khusus perlu di extend atau di override oleh subclass. 
Agar bisa membuat sebuah subclass dari sebuah superclass, maka perlu secara eksplisit menandari superclass dengan modifier open. Modifier ini juga berlaku pada semua properti superclass atau method yang dapat di override oleh subclass.
1
2
3
open class Student {
 
}
Hal ini dapat mengubah modifier open sebelum kata kunci class. sekarang sudah menginstruksikan kompiler untuk memerbolehkan kelas Student untuk di extend oleh kelas lain. 
Seperti yang sudah dijelaskan, anggota sebuah kelas Kotlin juga final secara otomatis. 
1
2
3
4
5
6
open class Student {
     
    open fun schoolFees(): BigDecimal {
       // do implementation
    }
}
Pada kode di atas, itu menandai fungsi schoolFees sebagai open—dengan begitu subclass dapat meng-override-nya.
01
02
03
04
05
06
07
08
09
10
open class GraduateStudent : Student() {
 
    override fun schoolFees(): BigDecimal {
        return super.schoolFees() + calculateSchoolFees()
    }
 
    private fun calculateSchoolFees(): BigDecimal {
        // calculate and return school fees
    }
}
Di sini, fungsi schoolFees yang sudah dibuka dari superclass Student di-override oleh kelas GraduateStudent—dengan menambahkan modifier overridesebelum kata kunci fun. Harus diingat adalah bahwa jika meng-override sebuah anggota dari superclass atau interface, member yang meng-override-nya juga akan menjadi open secara otomatis seperti pada contoh berikut:
01
02
03
04
05
06
07
08
09
10
class ComputerScienceStudent : GraduateStudent() {
 
    override fun schoolFees(): BigDecimal {
        return super.schoolFees() + calculateSchoolFess()
    }
 
    private fun calculateSchoolFess(): BigDecimal {
        // calculate and return school fees
    }
}
Meskipun tidak menandai method schoolFees() di dalam kelas GraduateStudent dengan modifier open, masih dapat meng-override-nya, seperti yang lakukan pada kelas ComputerScienceStudent. Jika ingin mencegah hal ini, maka harus menandai member tadi dengan kata kunci final
Ingat bahwa hal ini bisa menambah fungsionalitas ke dalam sebuah kelas—meskipun dideklarasikan final—menggunakan extensino functino milik Kotlin. 
Jika superclass kita memiliki konstruktor utama seperti ini:
1
2
3
open class Student(val firstName: String, val lastName: String) {
    // ...
}
Maka semua subclass harus memanggil konstruktor utama miliki superclass.
1
2
3
open class GraduateStudent(firstName: String, lastName: String) : Student(firstName, lastName) {
    // ...
}
Hal ini dapat membuat objek dari kelas GraduteStudent seperti biasa. 
1
2
val graduateStudent = GraduateStudent("Jon", "Snow")
println(graduateStudent.firstName) // Jon
Jika subclass ingin memanggil konstruktor superclass dari konstruktor keduanya,  gunakan kata kunci super (mirip dengan cara kerja konstruktor superclass di Java).
1
2
3
4
5
6
7
8
open class GraduateStudent : Student {
    // ...
    private var thesis: String = ""
     
    constructor(firstName: String, lastName: String, thesis: String) : super(firstName, lastName) {
        this.thesis = thesis
    }
}
Hal lain yang bisa dilakukan di Kotlin adalah memberikan sebuah alias.
Lihat contoh berikut.
1
data class Person(val firstName: String, val lastName: String, val age: Int)
Pada contoh di atas memberikan alias untuk String dan Int di properti milik Person dengan modifier typealias di Kotlin. Modifier ini dipakai untuk membuat sebuah alias dari semua jenis tipe data di Kotin—termasuk yang baru saja dibuat. 
1
2
3
4
typealias Name = String
typealias Age = Int
 
data class Person(val firstName: Name, val lastName: Name, val age: Age)
Seperti yang dapat dilihat, pada pembuatan sebuah alias Name dan Age untuk tipe String dan Int.  sekarang dapat menimpa firstName dan lastName menggunakan tipe data alias Name—juga Int untuk tipe Age. Ingat bahwa hal ini tidak membuat tipe data baru,  hanya membuat alias atau nama lain dari sebuah tipe data. 

Memunculkan Simbol & Emoji Pada OS Mac

  Memunculkan Simbol & Emoji  1. Buka aplikasi Pages / Notes pada Macbook. 2. Klik pada Menubar Edit --> Pilih Emoji and Symbols a...