CodeGym /Java Blog /Acak /Masalah apa yang dipecahkan oleh pola desain adaptor?
John Squirrels
Level 41
San Francisco

Masalah apa yang dipecahkan oleh pola desain adaptor?

Dipublikasikan di grup Acak
Pengembangan perangkat lunak dipersulit oleh komponen yang tidak kompatibel yang perlu bekerja sama. Misalnya, jika Anda perlu mengintegrasikan perpustakaan baru dengan platform lama yang ditulis dalam versi Java sebelumnya, Anda mungkin menemukan objek yang tidak kompatibel, atau lebih tepatnya antarmuka yang tidak kompatibel. Masalah apa yang dipecahkan oleh pola desain adaptor?  - 1Apa yang harus dilakukan dalam kasus ini? Tulis ulang kodenya? Kami tidak dapat melakukan itu, karena menganalisis sistem akan memakan banyak waktu atau logika internal aplikasi akan dilanggar. Untuk mengatasi masalah ini, pola adaptor telah dibuat. Ini membantu objek dengan antarmuka yang tidak kompatibel untuk bekerja sama. Mari kita lihat cara menggunakannya!

Lebih lanjut tentang masalahnya

Pertama, kami akan mensimulasikan perilaku sistem lama. Misalkan itu menghasilkan alasan untuk terlambat bekerja atau sekolah. Untuk melakukan ini, ia memiliki Excuseantarmuka yang memiliki generateExcuse(), likeExcuse()dan dislikeExcuse()metode.

public interface Excuse {
   String generateExcuse();
   void likeExcuse(String excuse);
   void dislikeExcuse(String excuse);
}
Kelas WorkExcusemengimplementasikan antarmuka ini:

public class WorkExcuse implements Excuse {
   private String[] excuses = {"in an incredible confluence of circumstances, I ran out of hot water and had to wait until sunlight, focused using a magnifying glass, heated a mug of water so that I could wash.",
   "the artificial intelligence in my alarm clock failed me, waking me up an hour earlier than normal. Because it is winter, I thought it was still nighttime and I fell back asleep. Everything after that is a bit hazy.",
   "my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia."};
   private String [] apologies = {"This will not happen again, of course. I'm very sorry.", "I apologize for my unprofessional behavior.", "There is no excuse for my actions. I am not worthy of this position."};

   @Override
   public String generateExcuse() { // Randomly select an excuse from the array
       String result = "I was late today because " + excuses[(int) Math.round(Math.random() + 1)] + "\\n" +
               apologies[(int) Math.round(Math.random() + 1)];
       return result;
   }

   @Override
   public void likeExcuse(String excuse) {
       // Duplicate the element in the array so that its chances of being chosen are higher
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Remove the item from the array
   }
}
Mari kita uji contoh kita:

Excuse excuse = new WorkExcuse();
System.out.println(excuse.generateExcuse());
Keluaran:

"I was late today because my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia.
I apologize for my unprofessional behavior.
Sekarang bayangkan Anda telah meluncurkan layanan penghasil alasan, mengumpulkan statistik, dan memperhatikan bahwa sebagian besar pengguna Anda adalah mahasiswa. Untuk melayani grup ini dengan lebih baik, Anda meminta pengembang lain untuk membuat sistem yang menghasilkan alasan khusus untuk mahasiswa. Tim pengembangan melakukan riset pasar, memberi peringkat alasan, menghubungkan beberapa kecerdasan buatan, dan mengintegrasikan layanan dengan laporan lalu lintas, laporan cuaca, dan sebagainya. Sekarang Anda memiliki perpustakaan untuk menghasilkan alasan bagi mahasiswa, tetapi memiliki antarmuka yang berbeda: StudentExcuse.

public interface StudentExcuse {
   String generateExcuse();
   void dislikeExcuse(String excuse);
}
Antarmuka ini memiliki dua metode: generateExcuse, yang menghasilkan alasan, dan dislikeExcuse, yang mencegah alasan muncul lagi di masa mendatang. Pustaka pihak ketiga tidak dapat diedit, artinya Anda tidak dapat mengubah kode sumbernya. Apa yang kita miliki sekarang adalah sistem dengan dua kelas yang mengimplementasikan antarmuka Excuse, dan perpustakaan dengan SuperStudentExcusekelas yang mengimplementasikan StudentExcuseantarmuka:

public class SuperStudentExcuse implements StudentExcuse {
   @Override
   public String generateExcuse() {
       // Logic for the new functionality
       return "An incredible excuse adapted to the current weather conditions, traffic jams, or delays in public transport schedules.";
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Adds the reason to a blacklist
   }
}
Kode tidak dapat diubah. Hirarki kelas saat ini terlihat seperti ini: Masalah apa yang dipecahkan oleh pola desain adaptor?  - 2Versi sistem ini hanya bekerja dengan antarmuka Excuse. Anda tidak dapat menulis ulang kode: dalam aplikasi besar, membuat perubahan seperti itu bisa memakan waktu lama atau merusak logika aplikasi. Kami dapat memperkenalkan antarmuka dasar dan memperluas hierarki: Masalah apa yang dipecahkan oleh pola desain adaptor?  - 3Untuk melakukan ini, kami harus mengganti nama Excuseantarmuka. Tetapi hierarki ekstra tidak diinginkan dalam aplikasi serius: memperkenalkan elemen root yang sama akan merusak arsitektur. Anda harus menerapkan kelas perantara yang memungkinkan kami menggunakan fungsionalitas baru dan lama dengan kerugian minimal. Singkatnya, Anda memerlukan adaptor .

Prinsip di balik pola adaptor

Adaptor adalah objek perantara yang memungkinkan pemanggilan metode dari satu objek dipahami oleh yang lain. Mari terapkan adaptor untuk contoh kita dan beri nama Middleware. Adaptor kami harus mengimplementasikan antarmuka yang kompatibel dengan salah satu objek. Biarlah Excuse. Ini memungkinkan Middlewareuntuk memanggil metode objek pertama. Middlewaremenerima panggilan dan meneruskannya dengan cara yang kompatibel ke objek kedua. Berikut implementasi Middlewaredengan metode generateExcuseand dislikeExcuse:

public class Middleware implements Excuse { // 1. Middleware becomes compatible with WorkExcuse objects via the Excuse interface

   private StudentExcuse superStudentExcuse;

   public Middleware(StudentExcuse excuse) { // 2. Get a reference to the object being adapted
       this.superStudentExcuse = excuse;
   }

   @Override
   public String generateExcuse() {
       return superStudentExcuse.generateExcuse(); // 3. The adapter implements an interface method
   }

    @Override
    public void dislikeExcuse(String excuse) {
        // The method first adds the excuse to the blacklist,
        // Then passes it to the dislikeExcuse method of the superStudentExcuse object.
    }
   // The likeExcuse method will appear later
}
Pengujian (dalam kode klien):

public class Test {
   public static void main(String[] args) {
       Excuse excuse = new WorkExcuse(); // We create objects of the classes
       StudentExcuse newExcuse = new SuperStudentExcuse(); // that must be compatible.
       System.out.println("An ordinary excuse for an employee:");
       System.out.println(excuse.generateExcuse());
       System.out.println("\n");
       Excuse adaptedStudentExcuse = new Middleware(newExcuse); // Wrap the new functionality in the adapter object
       System.out.println("Using new functionality with the adapter:");
       System.out.println(adaptedStudentExcuse.generateExcuse()); // The adapter calls the adapted method
   }
}
Keluaran:

An ordinary excuse for an employee:
I was late today because my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia.
There is no excuse for my actions. I am not worthy of this position. Using new functionality with the adapter:
Alasan luar biasa yang disesuaikan dengan kondisi cuaca saat ini, kemacetan lalu lintas, atau keterlambatan jadwal angkutan umum. Metode generateExcusehanya meneruskan panggilan ke objek lain, tanpa perubahan tambahan. Metode tersebut dislikeExcusemengharuskan kami untuk terlebih dahulu memasukkan alasan tersebut ke dalam daftar hitam. Kemampuan untuk melakukan pemrosesan data perantara adalah alasan mengapa orang menyukai pola adaptor. Tetapi bagaimana dengan likeExcusemetodenya, yang merupakan bagian dari Excuseantarmuka tetapi bukan bagian dari StudentExcuseantarmuka? Fungsionalitas baru tidak mendukung operasi ini. Itu UnsupportedOperationExceptiondiciptakan untuk situasi ini. Dilempar jika operasi yang diminta tidak didukung. Mari kita gunakan. Beginilah Middlewaretampilan implementasi baru kelas:

public class Middleware implements Excuse {

   private StudentExcuse superStudentExcuse;

   public Middleware(StudentExcuse excuse) {
       this.superStudentExcuse = excuse;
   }

   @Override
   public String generateExcuse() {
       return superStudentExcuse.generateExcuse();
   }

   @Override
   public void likeExcuse(String excuse) {
       throw new UnsupportedOperationException("The likeExcuse method is not supported by the new functionality");
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // The method accesses a database to fetch additional information,
       // and then passes it to the superStudentExcuse object's dislikeExcuse method.
   }
}
Sekilas, solusi ini sepertinya tidak terlalu bagus, tetapi meniru fungsionalitasnya dapat memperumit situasi. Jika klien memperhatikan, dan adaptor didokumentasikan dengan baik, solusi seperti itu dapat diterima.

Kapan harus menggunakan adaptor

  1. Saat Anda perlu menggunakan kelas pihak ketiga, tetapi antarmukanya tidak kompatibel dengan aplikasi utama. Contoh di atas menunjukkan cara membuat objek adaptor yang membungkus panggilan dalam format yang dapat dipahami oleh objek target.

  2. Ketika beberapa subclass yang ada membutuhkan beberapa fungsi umum. Daripada membuat subclass tambahan (yang akan menyebabkan duplikasi kode), lebih baik menggunakan adaptor.

Keuntungan dan kerugian

Keuntungan: Adaptor menyembunyikan detail permintaan pemrosesan dari satu objek ke objek lainnya dari klien. Kode klien tidak berpikir untuk memformat data atau menangani panggilan ke metode target. Ini terlalu rumit, dan pemrogram malas :) Kerugian: Basis kode proyek diperumit oleh kelas tambahan. Jika Anda memiliki banyak antarmuka yang tidak kompatibel, jumlah kelas tambahan dapat menjadi tidak dapat dikelola.

Jangan bingung adaptor dengan fasad atau dekorator

Dengan hanya pemeriksaan dangkal, adaptor dapat dikacaukan dengan pola fasad dan dekorator. Perbedaan antara adaptor dan fasad adalah bahwa fasad memperkenalkan antarmuka baru dan membungkus seluruh subsistem. Dan dekorator, tidak seperti adaptor, mengubah objek itu sendiri, bukan antarmuka.

Algoritma langkah demi langkah

  1. Pertama, pastikan Anda memiliki masalah yang dapat dipecahkan oleh pola ini.

  2. Tentukan antarmuka klien yang akan digunakan untuk berinteraksi secara tidak langsung dengan objek yang tidak kompatibel.

  3. Jadikan kelas adaptor mewarisi antarmuka yang ditentukan pada langkah sebelumnya.

  4. Di kelas adaptor, buat bidang untuk menyimpan referensi ke objek yang diadaptasi. Referensi ini diteruskan ke konstruktor.

  5. Terapkan semua metode antarmuka klien di adaptor. Suatu metode dapat:

    • Meneruskan panggilan tanpa melakukan perubahan apa pun

    • Mengubah atau menambah data, menambah/mengurangi jumlah panggilan ke metode target, dll.

    • Dalam kasus ekstrem, jika metode tertentu tetap tidak kompatibel, lemparkan UnsupportedOperationException. Operasi yang tidak didukung harus didokumentasikan dengan ketat.

  6. Jika aplikasi hanya menggunakan kelas adaptor melalui antarmuka klien (seperti pada contoh di atas), maka adaptor dapat diperluas tanpa rasa sakit di masa mendatang.

Tentu saja, pola desain ini bukan obat mujarab untuk semua penyakit, tetapi dapat membantu Anda menyelesaikan masalah ketidakcocokan antara objek dengan antarmuka yang berbeda secara elegan. Pengembang yang mengetahui pola dasar beberapa langkah di depan mereka yang hanya tahu cara menulis algoritme, karena pola desain diperlukan untuk membuat aplikasi yang serius. Penggunaan kembali kode tidak begitu sulit, dan pemeliharaan menjadi menyenangkan. Itu saja untuk hari ini! Tapi kita akan segera mengenal berbagai pola desain :)
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION