JavaRush /Java Blog /Random-ID /Masalah apa yang dipecahkan oleh pola desain Adaptor?

Masalah apa yang dipecahkan oleh pola desain Adaptor?

Dipublikasikan di grup Random-ID
Pengembangan perangkat lunak seringkali diperumit oleh ketidakcocokan antar komponen yang bekerja satu sama lain. Misalnya, jika Anda perlu mengintegrasikan perpustakaan baru dengan platform lama yang ditulis dalam versi Java sebelumnya, Anda mungkin mengalami ketidakcocokan objek, atau lebih tepatnya, antarmuka. Apa yang harus dilakukan dalam kasus ini? Tulis ulang kodenya? Tapi ini tidak mungkin: menganalisis sistem akan memakan banyak waktu atau logika internal pekerjaan akan rusak. Masalah apa yang dipecahkan oleh pola desain Adaptor - 1Untuk mengatasi masalah ini, mereka membuat pola Adaptor, yang membantu objek dengan antarmuka yang tidak kompatibel untuk bekerja sama. Mari kita lihat cara menggunakannya!

Detail lebih lanjut tentang masalahnya

Pertama, mari kita simulasikan perilaku sistem lama. Katakanlah hal itu menimbulkan alasan untuk terlambat bekerja atau sekolah. Untuk melakukan ini, kami memiliki antarmuka Excuseyang berisi metode generateExcuse(), likeExcuse()dan dislikeExcuse().

public interface Excuse {
   String generateExcuse();
   void likeExcuse(String excuse);
   void dislikeExcuse(String excuse);
}
Antarmuka ini diimplementasikan oleh kelas WorkExcuse:

public class WorkExcuse implements Excuse {
   private String[] reasonOptions = {"по невероятному стечению обстоятельств у нас в доме закончилась горячая вода и я ждал, пока солнечный свет, сконцентрированный через лупу, нагреет кружку воды, чтобы я мог умыться.",
   "искусственный интеллект в моем будильнике подвел меня и разбудил на час раньше обычного. Поскольку сейчас зима, я думал что еще ночь и уснул. Дальше все How в тумане.",
   "предпраздничное настроение замедляет метаболические процессы в моем организме и приводит к подавленному состоянию и бессоннице."};
   private String[] sorryOptions = {"Это, конечно, не повторится, мне очень жаль.", "Прошу меня извинить за непрофессиональное поведение.", "Нет оправдания моему поступку. Я недостоин этой должности."};

   @Override
   public String generateExcuse() { // Случайно выбираем отговорку из массива
       String result = "Я сегодня опоздал, потому что " + reasonOptions[(int) Math.round(Math.random() + 1)] + "\n" +
               sorryOptions[(int) Math.round(Math.random() + 1)];
       return result;
   }

   @Override
   public void likeExcuse(String excuse) {
       // Дублируем элемент в массиве, чтобы шанс его выпадения был выше
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Удаляем элемент из массива
   }
}
Mari kita uji contohnya:

Excuse excuse = new WorkExcuse();
System.out.println(excuse.generateExcuse());
Kesimpulan:
Я сегодня опоздал, потому что предпраздничное настроение замедляет метаболические процессы в моем организме и приводит к подавленному состоянию и бессоннице. 
Прошу меня извинить за непрофессиональное поведение.
Sekarang bayangkan Anda meluncurkan layanan, mengumpulkan statistik, dan memperhatikan bahwa mayoritas pengguna layanan adalah mahasiswa. Untuk memperbaikinya demi kebutuhan grup ini, Anda memesan sistem pembuatan alasan dari pengembang lain khusus untuknya. Tim pengembang melakukan penelitian, menyusun rating, menghubungkan kecerdasan buatan, menambahkan integrasi dengan kemacetan lalu lintas, cuaca, dan lain sebagainya. Sekarang Anda memiliki perpustakaan untuk membuat alasan bagi siswa, tetapi antarmuka untuk berinteraksi dengannya berbeda - StudentExcuse:

public interface StudentExcuse {
   String generateExcuse();
   void dislikeExcuse(String excuse);
}
Antarmuka memiliki dua metode: generateExcuse, yang menghasilkan alasan, dan dislikeExcuse, yang memblokir alasan tersebut agar tidak muncul di masa mendatang. Perpustakaan pihak ketiga ditutup untuk diedit - Anda tidak dapat mengubah kode sumbernya. Hasilnya, di sistem Anda terdapat dua kelas yang mengimplementasikan antarmuka Excuse, dan sebuah perpustakaan dengan kelas SuperStudentExcuseyang mengimplementasikan antarmuka StudentExcuse:

public class SuperStudentExcuse implements StudentExcuse {
   @Override
   public String generateExcuse() {
       // Логика нового функционала
       return "Невероятная отговорка, адаптированная под текущее состояние погоды, пробки or сбои в расписании общественного транспорта.";
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Добавляет причину в черный список
   }
}
Kode tidak dapat diubah. Skema saat ini akan terlihat seperti ini: Masalah apa yang dipecahkan oleh pola desain Adaptor - 2?Versi sistem ini hanya bekerja dengan antarmuka Excuse. Anda tidak dapat menulis ulang kode: dalam aplikasi besar, perubahan tersebut dapat memakan waktu lama atau merusak logika aplikasi. Anda dapat menyarankan untuk memperkenalkan antarmuka utama dan meningkatkan hierarki: Masalah apa yang dipecahkan oleh pola desain Adaptor - 3Untuk melakukan ini, Anda perlu mengganti nama antarmuka Excuse. Namun hierarki tambahan tidak diinginkan dalam aplikasi serius: memperkenalkan elemen root yang sama akan merusak arsitektur. Anda harus menerapkan kelas perantara yang memungkinkan Anda menggunakan fungsionalitas baru dan lama dengan kerugian minimal. Singkatnya, Anda memerlukan adaptor .

Cara kerja pola Adaptor

Adaptor adalah objek perantara yang membuat panggilan ke metode pada satu objek dapat dimengerti oleh objek lainnya. Mari kita terapkan adaptor untuk contoh kita dan beri nama Middleware. Adaptor kita harus mengimplementasikan antarmuka yang kompatibel dengan salah satu objek. Biarlah Excuse. Berkat ini, Middlewareia dapat memanggil metode dari objek pertama. Middlewaremenerima panggilan dan meneruskannya ke objek kedua dalam format yang kompatibel. Seperti inilah implementasi metode Middlewaredengan generateExcusemetode dislikeExcuse:

public class Middleware implements Excuse { // 1. Middleware становится совместимым с an objectом WorkExcuse через интерфейс Excuse

   private StudentExcuse superStudentExcuse;

   public Middleware(StudentExcuse excuse) { // 2. Получаем ссылку на адаптируемый an object
       this.superStudentExcuse = excuse;
   }

   @Override
   public String generateExcuse() {
       return superStudentExcuse.generateExcuse(); // 3. Адаптер реализовывает метод интерфейса
   }

    @Override
    public void dislikeExcuse(String excuse) {
        // Метод предварительно помещает отговорку в черный список БД,
        // Затем передает ее в метод dislikeExcuse an object superStudentExcuse.
    }
   // Метод likeExcuse появятся позже
}
Pengujian (dalam kode klien):

public class Test {
   public static void main(String[] args) {
       Excuse excuse = new WorkExcuse(); // Создаются an objectы классов,
       StudentExcuse newExcuse = new SuperStudentExcuse(); // Которые должны быть совмещены.
       System.out.println("Обычная причина для работника:");
       System.out.println(excuse.generateExcuse());
       System.out.println("\n");
       Excuse adaptedStudentExcuse = new Middleware(newExcuse); // Оборачиваем новый функционал в an object-адаптер
       System.out.println("Использование нового функционала с помощью адаптера:");
       System.out.println(adaptedStudentExcuse.generateExcuse()); // Адаптер вызывает адаптированный метод
   }
}
Kesimpulan:
Обычная причина для работника:
Я сегодня опоздал, потому что предпраздничное настроение замедляет метаболические процессы в моем организме и приводит к подавленному состоянию и бессоннице.
Нет оправдания моему поступку. Я недостоин этой должности. Использование нового функционала с помощью адаптера
Alasan yang luar biasa, disesuaikan dengan kondisi cuaca saat ini, kemacetan lalu lintas atau gangguan jadwal angkutan umum. Metode ini generateExcusehanya mentransfer panggilan ke objek lain, tanpa transformasi tambahan. Metode ini dislikeExcusemengharuskan terlebih dahulu menempatkan alasan tersebut pada daftar hitam database. Pemrosesan data perantara tambahan adalah alasan mengapa pola Adaptor disukai. Tapi bagaimana dengan metode likeExcuseyang ada di antarmuka Excuse, tapi tidak di StudentExcuse? Operasi ini tidak didukung dalam fungsi baru. Untuk kasus ini, mereka memberikan pengecualian UnsupportedOperationException: akan dilempar jika operasi yang diminta tidak didukung. Ayo gunakan ini. Seperti inilah implementasi kelas barunya Middleware:

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("Метод likeExcuse не поддерживается в новом функционале");
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Метод обращается за дополнительной информацией к БД,
       // Затем передает ее в метод dislikeExcuse an object superStudentExcuse.
   }
}
Pada pandangan pertama, solusi ini tampaknya tidak berhasil, namun simulasi fungsionalitas dapat menyebabkan situasi yang lebih kompleks. Jika klien penuh perhatian dan adaptor terdokumentasi dengan baik, solusi ini dapat diterima.

Kapan menggunakan Adaptor

  1. Jika Anda perlu menggunakan kelas pihak ketiga, tetapi antarmukanya tidak kompatibel dengan aplikasi utama. Contoh di atas menunjukkan bagaimana objek shim dibuat yang membungkus panggilan dalam format yang dapat dimengerti oleh objek target.

  2. Ketika beberapa subkelas yang ada harus memiliki fungsi yang sama. Daripada subkelas tambahan (pembuatannya akan menyebabkan duplikasi kode), lebih baik menggunakan adaptor.

Keuntungan dan kerugian

Keuntungan: Adaptor menyembunyikan dari klien rincian pemrosesan permintaan dari satu objek ke objek lainnya. Kode klien tidak memikirkan pemformatan data atau menangani panggilan ke metode target. Itu terlalu rumit, dan pemrogramnya malas :) Kerugian: Basis kode proyek diperumit oleh kelas tambahan, dan jika ada banyak titik yang tidak kompatibel, jumlahnya dapat bertambah hingga ukuran yang tidak terkendali.

Jangan bingung dengan Fasad dan Dekorator

Setelah diperiksa secara dangkal, Adaptor dapat tertukar dengan pola Façade dan Dekorator. Perbedaan antara Adaptor dan Fasad adalah Fasad memperkenalkan antarmuka baru dan membungkus seluruh subsistem. Dekorator, tidak seperti Adaptor, mengubah objek itu sendiri, bukan antarmuka.

Algoritma implementasi langkah demi langkah

  1. Pertama, pastikan ada masalah yang bisa dipecahkan oleh pola ini.

  2. Tentukan antarmuka klien atas nama kelas lain yang akan digunakan.

  3. Implementasikan kelas adaptor berdasarkan antarmuka yang ditentukan pada langkah sebelumnya.

  4. Di kelas adaptor, buatlah bidang yang menyimpan referensi ke objek. Referensi ini diteruskan di konstruktor.

  5. Menerapkan semua metode antarmuka klien di adaptor. Caranya bisa:

    • Mentransfer panggilan tanpa modifikasi;

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

    • Sebagai upaya terakhir, jika metode tertentu tidak kompatibel, berikan UnsupportedOperationException, yang harus didokumentasikan.

  6. Jika aplikasi menggunakan adaptor hanya melalui antarmuka klien (seperti pada contoh di atas), ini akan memungkinkan adaptor diperluas tanpa kesulitan di masa mendatang.

Tentu saja, pola desain bukanlah obat mujarab untuk semua penyakit, tetapi dengan bantuannya Anda dapat memecahkan masalah ketidakcocokan objek dengan antarmuka berbeda dengan elegan. Seorang pengembang yang mengetahui pola-pola dasar berada beberapa langkah di atas mereka yang hanya mengetahui cara menulis algoritma, karena mereka diperlukan untuk membuat aplikasi yang serius. Menggunakan kembali kode menjadi lebih mudah dan memeliharanya menjadi suatu kesenangan. Itu saja untuk hari ini! Tapi kami akan segera melanjutkan perkenalan kami dengan pola desain yang berbeda :)
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION