Interface

Pada sesi ini akan dibahas apa itu Interface dan kapan menggunakannya

Interface adalah adalah kumpulan definisi method yang tidak memiliki isi (hanya definisi saja) yang dibungkus dengan nama tertentu.

Interface merupakan tipe data. Nilai objek bertipe interface zero value-nya adalah nil. Interface mulai bisa digunakan jika sudah ada isinya, yaitu objek konkret yang memiliki definisi method yang sama dengan yang ada di interface.

type BangunDatar interface {
    luas() int
    keliling() int
}

Lalu yang menjadi pertanyaan, kenapa dan kapan menggunakan Interface?

Menulis kode yang fleksibel, dapat digunakan kembali, dan modular sangat penting dalam mengembangkan program. Ini juga adalah kenapa Go dibuat. Go sangat mendukung penulisan code yang clean, simple, reliable, dan efficient.

Jadi Interface sebenarnya adalah tools yang bisa kita pakai atau tidak. Tetapi Interface dapat membuat kode menjadi clean, shorter, dan more readable.

Mendefenisikan Behaviour

Sebelum masuk ke contoh Interface lebih detail, mari kita lihat studi kasus berikut:

package main

import "fmt"

type Persegi struct {
	sisi float64
}

func (persegi Persegi) luas() float64 {
	return persegi.sisi * persegi.sisi
}

type PersegiPanjang struct {
	panjang float64
	lebar   float64
}

func (persegiPanjang PersegiPanjang) luas() float64 {
	return persegiPanjang.panjang * persegiPanjang.lebar
}

type Segitiga struct {
	alas   float64
	tinggi float64
}

func (segitiga Segitiga) luas() float64 {
	return 0.5 * (segitiga.alas * segitiga.tinggi)
}

func main() {
	p := Persegi{sisi: 5}
	luasPersegi := luasBangunDatar(p)
	fmt.Println(luasPersegi)

	pp := PersegiPanjang{panjang: 4, lebar: 6}
	luasPersegiPanjang := luasBangunDatar(pp)
	fmt.Println(luasPersegiPanjang)

	s := Segitiga{alas: 20, tinggi: 10}
	luasSegitiga := s.luas()
	fmt.Println(luasSegitiga)
}

Dari kode di atas tidak ada yang salah. Jika dijalankan hasilnya pun akan sesuai.

Kita bisa lihat ada behaviour yang mirip diantara masing-masing struct yaitu sama-sama memiliki method luas . Untuk itu kita akan membuat interface untuk menampung method tersebut.

Mendefenisikan Interface

Untuk membuat tipe data Interface kita membutuhkan keyword type dan interface . Kita akan membuat interface bernama BangunDatar :

type BangunDatar interface {
    luas() float64
}

Lalu kita akan membuat function yang memiliki parameter dengan tipe data interface .

func luasBangunDatar(b BangunDatar) float64 {
	return b.luas()
}

Kita akan coba menggabungkan kedua kode di atas dengan kode sebelumnya:

package main

import "fmt"

type BangunDatar interface {
	luas() float64
}

type Persegi struct {
	sisi float64
}

func (persegi Persegi) luas() float64 {
	return persegi.sisi * persegi.sisi
}

type PersegiPanjang struct {
	panjang float64
	lebar   float64
}

func (persegiPanjang PersegiPanjang) luas() float64 {
	return persegiPanjang.panjang * persegiPanjang.lebar
}

type Segitiga struct {
	alas   float64
	tinggi float64
}

func (segitiga Segitiga) luas() float64 {
	return 0.5 * (segitiga.alas * segitiga.tinggi)
}

func main() {
	p := Persegi{sisi: 5}
	luasPersegi := luasBangunDatar(p)
	fmt.Println(luasPersegi)

	pp := PersegiPanjang{panjang: 4, lebar: 6}
	luasPersegiPanjang := luasBangunDatar(pp)
	fmt.Println(luasPersegiPanjang)

	s := Segitiga{alas: 20, tinggi: 10}
	luasSegitiga := s.luas()
	fmt.Println(luasSegitiga)
}

func luasBangunDatar(b BangunDatar) float64 {
	return b.luas()
}

Jadi fungsi luasBangunDatar tidak memperdulikan parameter nilai dari masing-masing bangun datar. Kita dapat menambahkan sebanyak mungkin bangun datar yang kita ingin hitung luasnya denga catatan struct harus memiliki method yang terdaftar pada interface dan memiliki isi sesuai dengan konteksnya masing-masing.

Studi kasus #2

Perhatikan kode di bawah ini:

package main

import "fmt"

type Article struct {
    Title  string
    Author string
}

func (a Article) String() string {
    return fmt.Sprintf("The %q article was written by %s.", a.Title, a.Author)
}

type Book struct {
    Title  string
    Author string
    Pages  int
}

func (b Book) String() string {
    return fmt.Sprintf("The %q book was written by %s.", b.Title, b.Author)
}

type Stringer interface {
    String() string
}

func main() {
    a := Article{
        Title:  "Understanding Interfaces in Go",
        Author: "Sammy Shark",
    }
    Print(a)

    b := Book{
        Title:  "All About Go",
        Author: "Jenny Dolphin",
        Pages:  25,
    }
    Print(b)
}

func Print(s Stringer) {
    fmt.Println(s.String())
}

Pada studi kasus di atas ada kesamaan behaviour yaitu kedua struct sama-sama memiliki method String untuk menampilkan teks informasi Buku dan Artikel.

Last updated