Penyematan vs Agregasi
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 38 dari 107.
Kamu telah mempelajari bahwa embedding mempromosikan field dan method ke struct luar. Namun, Go juga mendukung agregasi, yaitu saat kamu menyertakan struct lain sebagai field bernama. Memahami kapan harus menggunakan masing-masing pendekatan adalah kunci untuk desain yang baik.
Dengan embedding, kamu menghilangkan nama field, dan anggota tipe di dalamnya dapat diakses secara langsung:
type Writer struct{}
func (w Writer) Write() string { return "writing" }
type Document struct {
Writer // embedding, tanpa nama field
}
d := Document{}
d.Write() // akses langsung
Dengan agregasi, kamu memberi field nama eksplisit, sehingga nama itu diperlukan untuk mengakses tipe di dalamnya:
type Document struct {
writer Writer // agregasi, field bernama
}
d := Document{writer: Writer{}}
d.writer.Write() // harus menggunakan nama field
Perbedaan utamanya terletak pada hubungan yang kamu nyatakan. Embedding menunjukkan hubungan "is-a", yaitu tipe luar mengambil identitas tipe dalam. Aggregation menunjukkan hubungan "has-a", yaitu tipe luar hanya berisi tipe dalam.
Gunakan embedding saat kamu ingin tipe luar memenuhi interface yang diimplementasikan oleh tipe dalam, atau saat akses langsung ke method membuat API lebih rapi. Gunakan aggregation saat tipe dalam merupakan detail implementasi yang tidak seharusnya diekspos, atau saat kamu ingin mengontrol secara eksplisit cara tipe dalam diakses.
Tantangan
MudahMari buat sistem pembuatan laporan yang menunjukkan kapan sebaiknya menggunakan embedding dibandingkan aggregation. Kamu akan membuat sistem dengan beberapa komponen yang dapat diakses secara langsung (embedding), sementara komponen lainnya tetap menjadi detail implementasi internal (aggregation).
Kamu akan mengatur kodemu dalam tiga file:
formatter.go: Buat structFormatterdengan fieldStyle(string) dan methodFormat(text string) stringyang mengembalikan teks yang dibungkus dengan style, seperti[Style] text [/Style]. Ini akan menjadi helper internal yang tidak boleh diekspos secara langsung.report.go: Buat dua struct yang menangani pembuatan laporan dengan cara berbeda:- Struct
Metadatadengan fieldAuthordanDate. Ini merepresentasikan informasi publik yang seharusnya dapat diakses secara langsung. - Struct
Reportdengan fieldTitleyang menyematkanMetadata(agar author dan date dapat diakses secara langsung), tetapi menggunakan aggregation untukFormatter(sebagai detail implementasi internal dengan field bernamaformatter).
Generate() stringkeReportyang menggunakan formatter internal untuk memformat judul dan menyertakan metadata.- Struct
main.go: Baca detail laporan dari input, lalu buatReportdengan metadata yang disematkan dan formatter yang diagregasikan. Tunjukkan perbedaannya dengan mengakses author secara langsung pada report (melalui embedding), lalu membuat laporan berformat (yang menggunakan formatter tersembunyi secara internal).
Input berikut akan diberikan:
- Baris 1: Judul laporan
- Baris 2: Nama author
- Baris 3: Tanggal
- Baris 4: Style formatter
Method Format-mu harus mengembalikan:
[Style] text [/Style]Method Generate-mu harus mengembalikan:
[formatted title]
Author: [Author], Date: [Date]Dalam file main-mu, cetak tiga baris:
- Author yang diakses secara langsung pada Report (menunjukkan bahwa embedding membuat field dapat diakses secara langsung)
- Date yang diakses melalui nama tipe yang disematkan (
report.Metadata.Date) - Hasil pemanggilan
Generate()
Contohnya, jika diberikan Quarterly Results, Jane Doe, 2024-01-15, dan BOLD, outputmu seharusnya:
Jane Doe
2024-01-15
[BOLD] Quarterly Results [/BOLD]
Author: Jane Doe, Date: 2024-01-15Perhatikan bahwa Author dan Date dapat diakses secara langsung pada Report melalui embedding, sedangkan formatter tetap tersembunyi. Kamu tidak dapat memanggil report.Format() secara langsung karena formatter diagregasikan dengan field bernama. Ini menunjukkan penerapan hubungan "is-a" dibandingkan "has-a".
Coba sendiri
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
title := scanner.Text()
scanner.Scan()
author := scanner.Text()
scanner.Scan()
date := scanner.Text()
scanner.Scan()
style := scanner.Text()
// TODO: Buat struct Metadata yang berisi penulis dan tanggal
// TODO: Buat Formatter dengan gaya yang diberikan
// TODO: Buat Report yang menyematkan Metadata dan menggabungkan Formatter
// TODO: Cetak penulis yang diakses langsung melalui Report (penyematan membuat field dapat diakses langsung)
// TODO: Cetak tanggal yang diakses melalui nama tipe yang disematkan (report.Metadata.Date)
// TODO: Cetak hasil pemanggilan Generate()
// Hindari peringatan tentang variabel yang tidak digunakan (hapus baris-baris ini saat kamu menggunakan variabelnya)
_ = title
_ = author
_ = date
_ = style
}
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