Pola Adapter
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 92 dari 107.
Pola Adapter memungkinkan antarmuka yang tidak kompatibel untuk bekerja sama dengan membungkus tipe yang sudah ada menggunakan antarmuka baru. Command mengenkapsulasi tindakan, sedangkan Adapter menerjemahkan satu antarmuka ke antarmuka lain yang diharapkan client.
Bayangkan kamu memiliki printer lama yang menggunakan tanda tangan method berbeda dari yang diharapkan aplikasimu:
// Interface tujuan yang digunakan aplikasimu
type Printer interface {
Print(text string) string
}
// Printer lama dengan interface yang tidak kompatibel
type OldPrinter struct{}
func (o OldPrinter) PrintDocument(doc string, copies int) string {
return fmt.Sprintf("Old printer: %s (x%d)", doc, copies)
}Adapter membungkus tipe lama dan mengimplementasikan antarmuka yang diharapkan:
type OldPrinterAdapter struct {
oldPrinter OldPrinter
}
func (a OldPrinterAdapter) Print(text string) string {
return a.oldPrinter.PrintDocument(text, 1)
}Sekarang printer lama bekerja dengan lancar menggunakan kode yang mengharapkan antarmuka Printer:
func PrintMessage(p Printer, msg string) string {
return p.Print(msg)
}
adapter := OldPrinterAdapter{oldPrinter: OldPrinter{}}
result := PrintMessage(adapter, "Hello") // "Old printer: Hello (x1)"Pola Adapter sangat berguna saat mengintegrasikan library pihak ketiga, bekerja dengan kode lama, atau saat kamu perlu menggunakan class yang sudah ada tetapi tidak sesuai dengan kebutuhan interface-mu. Pola ini berfungsi sebagai jembatan tanpa mengubah kode asli.
Tantangan
MudahMari bangun sistem pemutar media menggunakan pola Adapter! Kamu memiliki pemutar audio modern yang mengharapkan antarmuka terpadu, tetapi kamu perlu mengintegrasikan peralatan audio lama yang menggunakan tanda tangan method yang sama sekali berbeda. Adapter-mu akan menjembatani kesenjangan ini, sehingga perangkat keras lama dapat bekerja dengan lancar bersama sistem baru.
Kamu akan mengatur kodemu dalam tiga file:
player.go: Definisikan antarmuka target dan perangkat audio lama.Buat antarmuka
AudioPlayeryang diharapkan sistem modernmu, dengan methodPlay(track string) stringyang menerima nama trek dan mengembalikan pesan pemutaran.Definisikan juga perangkat lama yang tidak sesuai dengan antarmuka ini:
- struct
VinylPlayerdengan fieldSpeedRPM(int). Struct ini memiliki methodDropNeedle(record string, side string) stringyang mengembalikanPlaying [record] ([side] side) at [speed]rpm
Antarmuka VinylPlayer tidak kompatibel dengan AudioPlayer. Antarmuka ini memerlukan dua parameter dan menggunakan nama method yang sama sekali berbeda.
- struct
adapter.go: Buat adapter yang membuat perangkat lama kompatibel.Buat struct
VinylAdapteryang membungkusVinylPlayerdan menerapkan antarmukaAudioPlayer. SaatPlaydipanggil, adapter harus memanggil methodDropNeedlemilik pemutar vinyl, dengan nilai defaultAuntuk parameter sisi.Buat juga pemutar modern sebagai pembanding:
- struct
DigitalPlayer: methodPlay-nya mengembalikanStreaming: [track]
- struct
main.go: Tunjukkan kedua pemutar bekerja melalui antarmuka yang sama.Buat fungsi
PlayMusic(player AudioPlayer, track string) stringyang menggunakan antarmuka untuk memutar musik. Fungsi ini tidak perlu mengetahui atau memedulikan apakah yang digunakan adalah pemutar digital atau pemutar vinyl yang diadaptasi.Baca tipe pemutar (
digitalatauvinyl), lalu jika tipenya vinyl, baca juga kecepatan RPM. Setelah itu, baca nama trek. Buat pemutar yang sesuai (gunakan adapter untuk vinyl), putar trek melalui fungsiPlayMusic-mu, lalu cetak hasilnya.
Input berikut akan diberikan:
- Baris 1: Tipe pemutar (
digitalatauvinyl) - Baris 2: Kecepatan RPM (hanya jika tipenya vinyl)
- Baris terakhir: Nama trek yang akan diputar
Contohnya, jika diberikan:
digital
Bohemian RhapsodyOutput-mu seharusnya:
Streaming: Bohemian RhapsodyDan jika diberikan:
vinyl
33
Abbey RoadOutput-mu seharusnya:
Playing Abbey Road (A side) at 33rpmDan jika diberikan:
vinyl
45
Blue MondayOutput-mu seharusnya:
Playing Blue Monday (A side) at 45rpmPerhatikan bahwa fungsi PlayMusic bekerja dengan cara yang sama pada kedua pemutar. Fungsi ini sama sekali tidak mengetahui bahwa pemutar vinyl sebenarnya diadaptasi dari antarmuka yang sama sekali berbeda. Adapter menerjemahkan pemanggilan antarmuka modern ke format lama di balik layar!
Coba sendiri
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
// PlayMusic menggunakan interface AudioPlayer untuk memutar musik
// Fungsi ini bekerja dengan implementasi AudioPlayer apa pun
// TODO: Implementasikan fungsi ini untuk memanggil player.Play(track) dan mengembalikan hasilnya
func PlayMusic(player AudioPlayer, track string) string {
// TODO: Implementasikan fungsi ini
return ""
}
func main() {
reader := bufio.NewReader(os.Stdin)
// Baca tipe pemutar
playerType, _ := reader.ReadString('\n')
playerType = strings.TrimSpace(playerType)
var player AudioPlayer
var track string
if playerType == "vinyl" {
// Baca kecepatan RPM untuk piringan hitam
rpmStr, _ := reader.ReadString('\n')
rpmStr = strings.TrimSpace(rpmStr)
rpm, _ := strconv.Atoi(rpmStr)
// Baca nama lagu
track, _ = reader.ReadString('\n')
track = strings.TrimSpace(track)
// TODO: Buat VinylPlayer dengan RPM yang diberikan
// TODO: Bungkus dengan VinylAdapter
// TODO: Tetapkan ke variabel player
_ = rpm // Hapus baris ini saat kamu menggunakan rpm
} else {
// Baca nama lagu
track, _ = reader.ReadString('\n')
track = strings.TrimSpace(track)
// TODO: Buat DigitalPlayer
// TODO: Tetapkan ke variabel player
}
// TODO: Panggil PlayMusic dan cetak hasilnya
_ = player // Hapus baris ini saat kamu menggunakan player
_ = track // Hapus baris ini saat kamu menggunakan track
}
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 File11Pustaka Standar & OOP
io.Reader & io.Writersort.InterfaceAntarmuka fmt.Stringerencoding/json dengan StructAntarmuka http.HandlerRingkasan, Model REST API14Pola Desain Bagian 2
Pola CommandPola AdapterPola DecoratorPola Template MethodPola StatePola CompositeMiddleware sebagai Decorator3Pointer 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