# Pseudo OOP

Golang bukan merupakan bahasa pemrograman yang berorientasi objek. Tapi golang memiliki fitur seperti type, struct, method, reference dan interface yang memungkinkan untuk melakukan pemrograman yang mirip dengan OOP.

## struct

* sebuah tipe data abstract
* berisi dari kumpulan dari berbagai type
* struct bisa digunakan dalam konsep class

```go
type User struct {
    ID uint64
    Name string    
}

func main() {
    var user User
    user.ID = 1
    user.Name = "Jacky"
    fmt.Printf("%v\n", user)
    println(user.Name)

    user2 := User{ID: 2, Name: "JetLee"}
    fmt.Printf("%v\n", user2)
    println(user2.Name)
}
```

## Method

* Kita bisa mendefiniskan suatu method pada sebuah type.
* Method adalah fungsi yang mempunyai argumen khusus receiver berupa type.

```go
package main

type MyStr string

func (m MyStr) Salam() {
    m = "Selamat Pagi"
    println(m)
}

func main() {
    var str MyStr
    str.Salam()
}
```

* Type yang bisa dibuatkan method adalah type local, yaitu type yang ada dalam paket yang sama dengan method yang dibuat.

```go
package main

// ini error karena string bukan type local dalam paket main
func (m string) Salam() {
    m = "Selamat Pagi"
    println(m)
}

func main() {
    var str string
    str.Salam()
}
```

* Receiver bisa berupa pointer

```go
package main

type myStr string

func (m *myStr) Change() {
    *m = myStr("Selamat Sore")
}

func (m *myStr) Print() {
    println(*m)
}

func main() {
    str := myStr("Selamat Pagi")
    str.Print()
    str.Change()
    str.Print()
}
```

## Interface

* Interface berisi kumpulan yang berisi method yang abstract

```go
type i interface{
    method()
}
```

* Type lain akan mengimplementasikan method dalam interface
* Tidak ada perintah implement, suatu interface akan dipenuhi secara implisit begitu ada yang mengimplementasikannya

```go
package main

type i interface {
    method()
}

type myStr string

func (m *myStr) method() {
    println(*m)
}

func main() {
    var i i
    str := myStr("Hello")
    i = &str
    i.method()
}
```

* Jika suatu interface diinisiasi tapi tidak ada yang mengimplementasikannya akan terjadi error nil pointer dereference

```go
package main

type i interface {
    method()
}

func main() {
    var i i
    i.method()
}
```

* Isi interface dapat dibayangkan sebagai sebuah pasangan nilai dan sebuah tipe: `(nilai, type)`

```go
package main

type i interface{
    method()
}

type myStr string

func (m *myStr) method() {
    println(*m)
}

func main() {
    var i i
    str := myStr("Hello")
    i = &str
    i.method()
        describe(i)
}

func describe(i I) {
    fmt.Printf("(%v, %T)\n", i, i)
}
```

## Interface Kosong

* Interface kosong merupakan interface yang tidak memiliki method
* Untuk mengklaim nilai interface harus dilakukan type asserting

```go
var a interface{}
a = "string"
println(a.(string))

a = false
println(a.(bool))
if value, ok := a.(bool); ok {
    println(value)
}

myMap := map[string]interface{}{"Satu": true, "Dua": "string", "Tiga": uint(3)}
println(myMap["Satu"].(bool))
println(myMap["Dua"].(string))
println(myMap["Tiga"].(uint))
```

* Penggunaan switch type dalam melakukan asserting

```go
package main

type myStr string

func main() {
    var a interface{}
    a = myStr("Jacky")

    switch t := a.(type) {
        case string :
            println("type string", t)
        case bool :
            println("type bool", t)
        case myStr :
            println("type myStr", t)
        default :
            println("type lainnya", t)
    }
}
```

## Pseudo Object

* tidak ada class dalam go, tapi kita bisa menggunakan type
* variable class diganti dengan type struct
* method class diganti dengan method dengan pointer reference
* gunakan kata kunci new() untuk membuat object

```go
package main

import (
    "fmt"
)

type becak struct {
    roda  int
    warna string
}

func (o *becak) caraJalan() string {
    return "dikayuh"
}

func main() {
    becak1 := becak{roda: 3, warna: "biru"}
    fmt.Printf("%v, %T\n", becak1, becak1)
    println("cara jalan:", becak1.caraJalan())

    becak2 := &becak1
    fmt.Printf("%v, %T\n", becak2, becak2)
    println("cara jalan:", becak2.caraJalan())

    becak3 := new(becak)
    becak3.roda = 3
    becak3.warna = "merah"
    fmt.Printf("%v, %T\n", becak3, becak3)
    println("cara jalan:", becak3.caraJalan())
}
```

### Method Overloading

* Method overloading dimungkinkan dengan reference yang berbeda

```go
package main

import (
    "fmt"
)

type becak struct {
    roda  int
    warna string
}

type gerobak struct {
        roda int
        warna string
} 

func (o *becak) caraJalan() string {
    return "dikayuh"
}

func (o *gerobak) caraJalan() string {
    return "didorong"
}

func main() {
    becak := new(becak)
    println("becak", "cara jalan:", becak.caraJalan())

        gerobak := new(gerobak)
        println("gerobak", "cara jalan:", gerobak.caraJalan())
}
```

### Encapsulation

* Encapsulasi terjadi di level paket.
* Kita bisa memilih kode (type, variabel, fungsi dll) yang hendak diexport ke luar paket dan mana yang hanya bisa diakses dalam paket yang sama.
* Penamaan kode yang bersifat publik diawali dengan huruf besar.
* Penamaan kode yang bersifat privat diawali dengan huruf kecil.

```go
// file APP/latihan/kendaraan.go
package latihan

// Kendaraan interface
type Kendaraan interface {
    CaraJalan() string
    SetWarna(string)
    GetWarna() string
    GetRoda() int
}

type becak struct {
    roda  int
    warna string
}

func (o *becak) SetWarna(s string) {
    o.warna = s
}

func (o *becak) GetWarna() string {
    return o.warna
}

func (o *becak) GetRoda() int {
    return 3
}

func (o *becak) CaraJalan() string {
    return "dikayuh"
}

// NewBecak function untuk membuat objek becak
func NewBecak() Kendaraan {
    return &becak{}
}
```

```go
package main

import (
    "golang-essentials/latihan"
)

func main() {
    becak := latihan.NewBecak()
    becak.SetWarna("Biru")
    println(becak.CaraJalan())
    println("jumlah roda:", becak.GetRoda())
    println("warna:", becak.GetWarna())
}
```

### Inheritance

* Go memungkinkan inheritance melalui embedded berupa field anonim

```go
package main

import (
    "fmt"
)

type User struct {
    Name string
    Gender string
    Address
}

type Address struct {
    Street string
    Number string
    City string
    Zipcode string
}

func main () {
    user := new(User)
    user.Name = "Wiro"
    user.Gender = "Male"
    user.Street = "Marlioboro"
    user.Number = "212"
    user.City = "Jogja"

    fmt.Printf("%v", user)
}
```

* Tapi banyak programmer golang yang tidak menyarankan untuk melakukan inheritance. Melainkan melakukan pendekatan object composition.

### Object Composition

* Daripada melakukan pseudo inheritance melalui embedded, disarankan untuk melakukan object composition

```go
package main

import (
    "fmt"
)

type User struct {
    Name string
    Gender string
    Address Address
}

type Address struct {
    Street string
    Number string
    City string
    Zipcode string
}

func main () {
    user := new(User)
    user.Name = "Wiro"
    user.Gender = "Male"
    user.Address.Street = "Marlioboro"
    user.Address.Number = "212"
    user.Address.City = "Jogja"

    fmt.Printf("%v", user)
}
```

### Polymorphism

```go
package main

import "fmt"

type Hewan struct {
    Nama  string
    Nyata bool
}

func (c *Hewan) Cetak() {
    fmt.Printf("Nama: '%s', Nyata: %t\n", c.Nama, c.Nyata)
}

type HewanTerbang struct {
    Hewan
    PanjangSayap int
}

func (c HewanTerbang) Cetak() {
    fmt.Printf("Nama: '%s', Nyata: %t, PanjangSayap: %d\n", c.Nama, c.Nyata, c.PanjangSayap)
}

type Unicorn struct {
    Hewan
}

type Naga struct {
    HewanTerbang
}

type Pterodactilus struct {
    HewanTerbang
}

func NewPterodactyl(panjangSayap int) *Pterodactilus {
    p := new(Pterodactilus)
    p.Nama = "Pterodactilus"
    p.Nyata = true
    p.PanjangSayap = panjangSayap

    return p
}

func main() {
    hewan := new(Hewan)
    hewan.Nama = "Sembarang hewan"
    hewan.Nyata = false

    naga := new(Naga)
    naga.Nama = "Naga"
    naga.Nyata = false

    uni := new(Unicorn)
    uni.Nama = "Unicorn"
    uni.Nyata = false

    p1 := new(Pterodactilus)
    p1.Nama = "Pterodactilus"
    p1.Nyata = true
    p1.PanjangSayap = 5

    p2 := NewPterodactyl(8)

    hewan.Cetak()
    naga.Cetak()
    uni.Cetak()
    p1.Cetak()
    p2.Cetak()

    animals := []*Hewan{
        hewan,
        &naga.Hewan,
        &uni.Hewan,
        &p1.Hewan,
        &p2.Hewan,
    }
    fmt.Println("Cetak() melalui  embedded type Hewan")
    for _, c := range animals {
        c.Cetak()
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://golang-microservices.rijalasepnugroho.com/golang-fundamental/pseudo_oop.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
