Hai rekan penggiling pola!😲 Selamat datang di rangkaian Pola Desain! Ini adalah kumpulan artikel tempat saya menulis tentang pola untuk menyebarkan kebodohan mereka🙌

Saya sarankan Anda membaca artikel sebelumnya di mana Anda dapat memetik banyak pengetahuan:

Kemudian, seperti biasa, dukung O'Reilly Media karena buku mereka luar biasa: https://www.oreilly.com/library/view/head-first-design/9781492077992/

Struktur:

  • Pendahuluan
  • Masalah: Adaptor
  • Tambahan Bagian Satu
  • Masalah: Fasad
  • Prinsip desain yang harus diikuti
  • Tambahan Bagian Dua
  • Kode solusi akhir: Kedua Pola
  • Menggambar

❗️Pertama-tama saya memberikan penjelasan tentang Adaptor & kemudian beralih ke Fasad yang akan memakan waktu lebih sedikit. Ayo pergi☄️

Pola Adaptor & Fasad

Adaptor

Pendahuluan

Pola adalah pilihan bagus untuk terjun ke dunia OOP. Setidaknya bagi saya itu adalah pintu ajaib, pembukaan yang membantu saya memahami OOP bukan hanya sebagai kelas, warisan, komposisi, tetapi untuk menginternalisasikan SOLID😱 dari awal, lihat cara menyusun sistem yang kompleks dan seterusnya🧑🏼‍💻

Dan meskipun Anda tidak akan mengingat setiap pola di dunia (dan memang seharusnya tidak demikian), itu adalah solusi jitu, yang jika dipahami, akan membuka jalan dalam pikiran Anda menuju struktur yang lebih optimal, perangkat lunak yang lebih baik & sebagai hasilnya. , kamu menjadi SWE terkemuka😎

Masalah: Adaptor

Bayangkan Anda memiliki Klien yang mengetahui cara berinteraksi dengan suatu kelas.

Contoh dasar: Steker AC -> Soket. Lalu Anda pindah ke negara lain🎌 dan sekarang Anda menggunakan struktur berikut: Steker AC -› Adaptor Daya AC -› Soket

Adaptor dalam pemrograman bekerja dengan cara yang sama: mereka mengambil kelas Klien, menggabungkannya ke dalam antarmuka yang dikenal oleh kelas Akhir (mari kita bayangkan itu adalah Vendor kita ).

Tolong, perhatikan baik-baik kode di bawah ini. Saya awalnya berpikir bahwa polanya sangat mudah, tetapi terjebak dalam jurang kesalahpahaman dan kehilangan waktu😫

Pertama-tama amati contoh dasar adaptor ini, lalu saya akan membuat run-downnya

  1. Kami memiliki 2 antarmuka: Duck dan Turkey
  2. Setiap kelas memiliki implementasinya sendiri
  3. Bayangkan Klien mengetahui cara berinteraksi dengan antarmuka tipe Bebek, namun kita memiliki kelas yang mengimplementasikan antarmuka Turki (saya menulis MallardDuck sebagai contoh, tetapi Klien tidak tahu apa-apa tentang itu)
  4. Di Adaptor kami mengimplementasikan antarmuka yang ‼️beradaptasi‼️ yang dalam kasus kami adalah Duck
  5. Letakkan metode Adapt-to-Interface itu dan di dalamnya masukkan metode kelas sebenarnya yang digunakan (PS: sediakan instance kelas yang akan memanfaatkan metode tersebut di dalamnya), yang pada kode di atas adalah : .gobble() & turkeyFly()

Saya secara khusus memulai dengan contoh kode, selain artikel sebelumnya. Semoga catatan ini dapat membuat pernyataan Anda lebih lancar🙉

Sekarang, izinkan saya menggunakan sedikit kata kunci yang terkait dengan pola tersebut agar lebih bersifat akademis👨🏼‍🎓

  1. Klien diimplementasikan terhadap Antarmuka target, dengan Target adalah antarmuka yang Klien ketahui cara berinteraksi dengannya
  2. Adaptor mengimplementasikan antarmuka target untuk merutekan permintaan Klien. Pada contoh di atas TurkeyAdapter mengimplementasikan Antarmuka target yaitu Duck
  3. Instance yang digunakan di dalam adaptor adalah Antarmuka Adaptee (yaitu CoolTurkey kami yang disediakan untuk Adaptor mengimplementasikan antarmuka Turkey)
  4. Klien menerima respons dengan senang hati dan tidak pernah tahu ada ilmu hitam di balik pintu!🦹‍♂️

Sebenarnya ada beberapa peringatan yang akan saya bahas lebih lanjut di artikel

  • Adaptor memisahkan Klien dari kode akhir (antarmuka yang diimplementasikan). Jadi, Kode Klien & Final kami tidak perlu diubah jika ada bagian yang berubah (dan sering kali kami tidak dapat melakukannya)
  • Perhatikan bagaimana Adapter memetakan permintaan Klien bukan ke kelas konkret, namun antarmuka, yang berarti kita dapat menulis beberapa Adaptor untuk mengonversi berbagai kumpulan kelas

Tambahan Bagian Satu

  1. Sejujurnya ada 2 jenis Adaptor. Contoh di atas adalah Adaptor Objek kanonik dengan Warisan Tunggal dan Komposisi. Dan ini bagus (ditambah lagi kami tidak memiliki Banyak Warisan di Java & Kotlin). Namun, ada tipe kedua: Class Adapter yang menggunakan Multiple Inheritance & no Composition. Saya menulis kode dengan Python untuk menunjukkan kepada Anda tampilannya:

Lihat, kami memiliki 2 kelas abstrak (Dalam Python kami tidak memiliki antarmuka yang sebenarnya). Kemudian kami memiliki 2 kelas konkret. Terakhir, Adaptor menerima permintaan dari Klien yang mengetahui cara berbicara dengan Socket tipe AS => menempatkan abstract class soket AS sebagai objek pertama dalam Warisan dan mengimplementasikan metode tersebut. Objek kedua dalam warisan adalah kelas beton yang akan kita alihkan. Dalam kasus kami, ini EuSocket

Adaptor mana yang lebih baik? Tidak tahu🤔 & bahkan O'Reilly Media tidak mengklaim pemenangnya dalam buku tersebut. Masing-masing memiliki pro & kontra terkait dengan pendekatan Komposisi & Warisan.

2. Bagaimana jika kita tidak memiliki metode tertentu dalam kode yang digunakan? (Maksud saya, Kode adaptasi). Misalnya, klien/kode kita mengetahui cara berinteraksi dengan Iterator, namun pada kode terakhir kita terjebak dengan Enumerator.
* Catatan tambahan: Yang pertama lebih baru daripada yang terakhir.
Jadi, bisakah kita mengabaikannya? Sayangnya, hanya dengan bantuan Exception. Untuk kasus seperti itu tulis dokumentasi🤷‍♂️

Contoh kode O'Reilly Media:

Lihat, objek kita adalah enumerator , tetapi metode yang diekspos adalah iterator

3. Adaptor mungkin tertukar dengan Dekorator. Namun yang pertama membungkus objek ke antarmuka yang ada sementara yang kedua menambahkan tanggung jawab. Untuk mempelajari lebih lanjut, baca artikel saya yang ditujukan untuk Pola dekorator: https://medium.com/towardsdev/decorator-decorator-pattern-for-object-composition-kotlin-7cec92cbaf7b

Masalah: Fasad

Pola ini, dari sudut pandang saya, lebih mirip dengan hal-hal sehari-hari yang kita tulis✍🏻

Bayangkan, Anda mempunyai banyak kelas yang perlu Anda panggil secara berurutan. Selain itu, Anda memiliki Antarmuka dan kemudian diimplementasikan oleh beberapa kelas. Seperti puluhan hal seperti itu...👀 Mengapa tidak menyediakan contoh antarmuka yang diimplementasikan ke dalam satu kelas yang mencakup yang mengekspos metode di mana contoh tersebut memanggil metode mereka?🧐

               Facade class
                 * instance_one = newA()
                 * instance_two = newB()
               
                  methodA()
                     instance_one.callA()
                     instance_two.callAA()
                  
                  methodB()
                     instance_one.callB()
                     instance_two.callBB()
interface A                         interface B
    |                                   |
class newA implements A             class newB implements B
    * callA()                          * callAA()
    * callB()                          * callBB()

Saya harap Anda mendapatkan diagram kasar ini (saya akan membuat kodenya di bagian yang ditentukan)🤘

  • Jika Anda perlu mengakses metode komponen tingkat rendah tersebut -› Anda bebas menggunakannya
  • Kami memisahkan Klien yang membuat permintaan melalui Fasad dengan Sistem. Bagaimana jika antarmuka diubah dan implementasi kelas sudah siap❓❓Tidak perlu mengubah Klien kami (dan sering kali kami tidak bisa), tetapi lakukan kembali Fasad dan Anda akan tampil rapi!💯

Fasad tidak hanya menyederhanakan antarmuka, namun memisahkan Klien dari Sistem Final

Prinsip desain yang harus diikuti

  1. Prinsip Pengetahuan Paling Sedikit (Hukum Demeter): berbicaralah hanya dengan teman dekat Anda🌝

Singkatnya, ini berarti kita harus sangat sadar terhadap kelas-kelas yang kita gunakan saat mengembangkan sistem. Yaitu. jangan memanggil secara membabi buta beberapa metode dari kelas lain karena akan menjadi bumerang bagi bug🪲

Contoh pemanggilan metode yang buruk:

Kami memanggil metode pada instance yang dikembalikan dari metode lain:

  1. getThermometer() mengembalikan contoh
  2. Kami memanggil getTemperature() misalnya dari 1

Pedoman saat memanggil metode:

  1. dari kelas yang sama
  2. dari komponen kelas saat ini
  3. dari parameter (mungkin berupa objek) yang diteruskan ke metode
  4. dari objek yang dibuat/dibuat dalam metode

‼️Bahaya:‼️ jangan memanggil metode pada objek yang dikembalikan dari pemanggilan metode lain di dalam metode tersebut. Ini meningkatkan jumlah teman yang terkait dengan metode/kelas yang buruk dalam kasus kita (lihat contoh di atas untuk kasus seperti itu)

Izinkan saya menunjukkan kepada Anda dalam praktik bagaimana semuanya bekerja:

  1. kelas utama adalah Car tempat kita memicu metode start()
  2. Mari kita uraikan cara pemanggilan metode dalam suatu metode:
    * baris 30: gunakan metode pada parameter yang disediakan untuk metode tersebut
    * baris 32: gunakan metode pada komponen kelas , Mesin
    * baris 33: menggunakan metode kelas saat ini, Car
    * baris 34: menggunakan metode kelas yang dibuat/dibuat dalam metode

Terakhir, izinkan saya menunjukkan kepada Anda bagaimana Anda dapat mengubah pemanggilan metode dari atas (contoh buruk)🎉:

  1. Kita memanggil giveHouseTemperature() , namun kita tidak bisa begitu saja memanggil metode pada currentStation & kemudian langsung pada thermometer . Oleh karena itu, kami memisahkan pemanggilannya
  2. Pertama-tama, ambil termometer dari currentStation : gunakan metode pada komponen kelas saat ini
  3. Kemudian panggil metode di dalam kelas kami tempat kami menyediakan instance termometer
  4. giveTemperature() dipanggil berdasarkan parameter yang diberikan ke metode
  5. akhirnya hasilnya dikembalikan ke metode sebelumnya dan sampai ke kita🙌🏼

Bagian tambahan: Dua

  1. Prinsip Pengetahuan Paling Sedikit digunakan di dalam Pola fasad:
    * Klien hanya berinteraksi dengan Fasad: hal baik (satu teman)
  2. Kode sistem dapat ditingkatkan tanpa memengaruhi Klien (jika kami tidak mengubah hal-hal antarmuka. Dan jika demikian, hanya Fasad yang akan diubah)
  3. Jika Fasad itu sendiri menjadi bercampur dan kehilangan prinsip di atas : tambahkan pola Fasad tambahan di dalam Fasad utama kita

Kode solusi akhir: Kedua pola

Mari kita lihat kodenya🤟🏼

  • Pada awalnya kami memiliki pola Adaptor:


  1. main.kt merangkum permintaan Klien kami. Di sini kita membuat objek akhir dan memasukkannya ke dalam Adaptor yang mengimplementasikan Target Interface
  2. Jadi, TargetInterface.kt adalah antarmuka awalnya. Target.kt adalah kelas yang kami implementasikan
  3. AdapteeInterface.kt adalah antarmuka kode baru kami & Adaptee.kt adalah kelas implementasi baru kami
  4. Adapter.kt adalah Adaptor kami yang, sekali lagi, mengimplementasikan antarmuka OLD dan karenanya memperlihatkan metodenya. Namun kami memberikan instance BARU kami ke Adaptor sehingga kami memanggil metode tersebut on instance dari metode yang terekspos

Saya harap Anda mendapatkan strukturnya. Jika ada yang tidak bisa diklik -› tulis di komentar✌🏼

  • Sekarang kita beralih ke pola Fasad:


  1. ProjectorInterface.kt & AmplifierInterface.kt adalah antarmuka dari Sistem
  2. Projector.kt & Amplifier.kt adalah kelas konkrit yang mengimplementasikan antarmuka dari atas
  3. OurFacade.kt adalah Fasad itu sendiri yang memisahkan Sistem dari permintaan Klien
  4. main.kt adalah permintaan Klien kami. Kami menyediakan instance kelas ke Fasad. Ia memiliki metode yang sekarang ditarik oleh Klien. Di dalam metode tersebut kita mempunyai instance yang memanggil metodenya

Sekali lagi, jika Antarmuka Sistem diubah (dan implementasi kelas juga), kita tidak perlu melakukan perombakan besar-besaran pada Sistem Klien lainnya, namun sesuaikan saja Fasad

Menggambar🎨

Pada gambar Anda dapat melihat:

  • sisi kiri adalah Pola adaptor
  • sisi kanan adalah Pola fasad

Agak berantakan, tapi harap Anda memahami intinya💫

Luar✌🏼

Definisi akademis dari Pola Adaptor: adaptor berfungsi sebagai perantara yang mengubah antarmuka yang kita miliki sekarang di Sistem kita menjadi antarmuka yang diharapkan klien (yaitu telah ada di Sistem kita sebelumnya). Adaptor memungkinkan kelas-kelas bekerja sama yang tidak dapat melakukannya tanpa (Klien & Kode Akhir Kami) karena ketidakcocokan

Definisi akademis dari Pola Fasad: menyediakan antarmuka/titik akses terpadu ke sekumpulan antarmuka dalam sistem (yang diimplementasikan). Fasad adalah antarmuka tingkat tinggi (sebenarnya, ini bukan antarmuka, tetapi sebuah kelas, tetapi dalam terminologi klasik dikatakan demikian) yang menyederhanakan interaksi ke sistem tingkat rendah

Wah, banyak sekali infonya!🤯 Baca kembali baik-baik dan ajukan pertanyaan di kolom komentar jika ada yang kurang jelas💬

Anda dapat menemukan saya: