Mengapa Go Tidak Memiliki Pewarisan
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 34 dari 107.
Bahasa berorientasi objek tradisional seperti Java dan C++ menggunakan pewarisan untuk berbagi kode antar tipe. Child class memperluas parent class dan mewarisi semua field serta method-nya. Go sengaja tidak menyertakan fitur ini.
Pewarisan menciptakan keterikatan yang erat antara tipe. Saat parent class berubah, semua child class terdampak.
Hierarki pewarisan yang dalam menjadi sulit dipahami dan dipelihara. "Masalah class dasar yang rapuh" terjadi ketika perubahan pada class dasar secara tak terduga merusak class turunan.
Para perancang Go memilih pendekatan yang berbeda: komposisi daripada pewarisan. Alih-alih mengatakan "seekor Dog adalah Animal," Go mendorongmu untuk mengatakan "seekor Dog memiliki perilaku seperti Animal." Perubahan kecil ini menghasilkan kode yang lebih fleksibel dan mudah dipelihara.
Go mencapai penggunaan ulang kode melalui dua mekanisme yang sudah kamu pelajari:
- Antarmuka mendefinisikan kontrak perilaku tanpa detail implementasi
- Embedding struct memungkinkan tipe menyertakan tipe lain dan menggunakan kembali method-nya
Pertimbangkan perbandingan ini. Dalam OOP tradisional, kamu mungkin menulis class Dog extends Animal. Di Go, kamu menyematkan struct Animal di dalam Dog dan mengimplementasikan interface bersama. Hasilnya adalah fungsionalitas yang serupa dengan keterikatan yang lebih longgar antar tipe.
Bab ini membahas embedding struct secara mendalam, serta menunjukkan cara Go memperoleh manfaat pewarisan tanpa kekurangannya.
Tantangan
MudahMari buat sistem notifikasi yang menunjukkan pendekatan komposisi Go, bukan pewarisan. Kamu akan membuat tipe-tipe yang berbagi perilaku melalui interface dan penyematan struct, bukan hierarki class.
Kamu akan mengatur kodemu dalam tiga file:
notifier.go: Definisikan interfaceNotifierdengan satu methodNotify(message string) string. Buat juga structBaseNotifierdengan fieldNameyang akan disematkan oleh tipe-tipe lain. BeriBaseNotifiermethod bernamaFormat(message string) stringyang mengembalikan pesan dengan nama notifier di dalam tanda kurung siku sebagai awalan.channels.go: Buat dua tipe saluran notifikasi yang menyematkanBaseNotifierdan mengimplementasikan interfaceNotifier:EmailNotifierdengan field tambahanAddressSMSNotifierdengan field tambahanPhone
Notifysetiap tipe harus menggunakan methodFormatyang disematkan dan menyertakan informasi salurannya dalam output.main.go: Buat fungsi bernamaSendAlertyang menerima sembarangNotifierdan sebuah pesan, lalu mengembalikan hasil pemanggilanNotify. Baca detail notifikasi dari input, buat kedua tipe notifier, lalu tunjukkan cara keduanya dapat digunakan secara bergantian melalui interface.
Input berikut akan diberikan:
- Baris 1: Nama notifier untuk email
- Baris 2: Alamat email
- Baris 3: Nama notifier untuk SMS
- Baris 4: Nomor telepon
- Baris 5: Pesan peringatan
Method Format pada BaseNotifier harus mengembalikan:
[Name] messageMethod Notify harus mengembalikan:
- EmailNotifier:
Email to [Address]: [formatted message] - SMSNotifier:
SMS to [Phone]: [formatted message]
Contohnya, jika diberikan Alerts, user@mail.com, Urgent, 555-1234, dan Server down, outputmu seharusnya:
Email to user@mail.com: [Alerts] Server down
SMS to 555-1234: [Urgent] Server downPerhatikan bahwa kedua tipe notifier menggunakan kembali method Format dari BaseNotifier melalui penyematan, sementara masing-masing menyediakan implementasi Notify</code sendiri. Fungsi <code>SendAlert bekerja dengan sembarang Notifier tanpa mengetahui tipe konkretnya. Inilah contoh komposisi sebagai pengganti pewarisan.
Coba sendiri
package main
import (
"bufio"
"fmt"
"os"
)
// SendAlert menerima Notifier apa pun dan sebuah pesan, lalu mengembalikan hasil pemanggilan Notify
// TODO: Implementasikan fungsi SendAlert
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Baca nama pengirim notifikasi email
scanner.Scan()
emailName := scanner.Text()
// Baca alamat email
scanner.Scan()
emailAddress := scanner.Text()
// Baca nama pengirim notifikasi SMS
scanner.Scan()
smsName := scanner.Text()
// Baca nomor telepon
scanner.Scan()
phoneNumber := scanner.Text()
// Baca pesan peringatan
scanner.Scan()
alertMessage := scanner.Text()
// TODO: Buat EmailNotifier dengan emailName dan emailAddress
// TODO: Buat SMSNotifier dengan smsName dan phoneNumber
// TODO: Gunakan SendAlert untuk mengirim alertMessage melalui kedua pengirim notifikasi
// dan cetak hasilnya
// Hilangkan peringatan variabel yang belum digunakan (hapus baris ini saat kamu menggunakan variabel tersebut)
_ = emailName
_ = emailAddress
_ = smsName
_ = phoneNumber
_ = alertMessage
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Objek
1Dasar-Dasar OOP di Go
File EksternalWorkspace Go dan modulePaket dan ImporNama yang Diekspor dan Tidak DieksporPengantar OOP di Gostruct sebagai classMendefinisikan method pada structPointer receiver vs value receiverInisialisasi structFungsi KonstruktorUlasan: Kalkulator Sederhana4Interface
Pengenalan InterfaceImplementasi ImplisitInterface sebagai KontrakInterface Kosong (any)Type AssertionType SwitchKomposisi InterfaceInterface Stringer & ErrorUlasan: Kalkulator Bentuk7Enkapsulasi
Field yang Diekspor vs Tidak DieksporEnkapsulasi Tingkat PackageMethod Getter dan SetterPenyembunyian Informasi di GoRingkasan: Data Siswa10Generics (Go 1.18+)
Pengantar GenericsParameter TipeBatasan TipeStruct GenerikCara Alternatif untuk Method GenerikRingkasan Koleksi Generik2Mendalami Tipe dan Struct
Tipe Dasar dan KompositDefinisi Tipe KustomTag StructStruct AnonimStruct BersarangNilai Nol dan Nilai BawaanRangkuman: Buku Kontak5Komposisi daripada Pewarisan
Mengapa Go Tidak Memiliki PewarisanDasar Penyematan StructPromosi methodMenyematkan Beberapa StructPenyematan vs AgregasiMembayangi method yang DisematkanRangkuman: Hierarki Karyawan8Penanganan Error & OOP
Interface errorTipe Error KustomPembungkusan Error (fmt.Errorf)Error Sentinelerrors.Is() dan errors.As()Panic, Defer, dan RecoverRangkuman: Parser File3Pointer dan Memori
Dasar-Dasar Pointer di GoPointer ke StructPass by Value vs ReferenceFungsi new()Garbage Collection di GoRekap: Pembuat Linked List6Polimorfisme di Go
Polimorfisme melalui InterfaceDuck Typing di GoAturan Pemenuhan InterfaceKoleksi PolimorfikInjeksi DependensiRangkuman: Pemroses Pembayaran9Konkruensi & OOP
Dasar-dasar GoroutineChannel & KomunikasiChannel Ber-buffer vs Tanpa BufferPernyataan selectsync.Mutex & sync.RWMutexsync.WaitGroupDesain Struct yang Aman untuk ThreadRingkasan: Worker PoolLatihan sendiri: Compiler Go online