CodeGym /Blog Java /rawak /Apakah masalah yang diselesaikan oleh corak reka bentuk p...
John Squirrels
Tahap
San Francisco

Apakah masalah yang diselesaikan oleh corak reka bentuk penyesuai?

Diterbitkan dalam kumpulan
Pembangunan perisian menjadi lebih sukar oleh komponen yang tidak serasi yang perlu bekerjasama. Sebagai contoh, jika anda perlu menyepadukan perpustakaan baharu dengan platform lama yang ditulis dalam versi Java yang lebih awal, anda mungkin menghadapi objek yang tidak serasi atau antara muka yang tidak serasi. Apakah masalah yang diselesaikan oleh corak reka bentuk penyesuai?  - 1Apa yang perlu dilakukan dalam kes ini? Tulis semula kod? Kami tidak boleh berbuat demikian, kerana menganalisis sistem akan mengambil banyak masa atau logik dalaman aplikasi akan dilanggar. Untuk menyelesaikan masalah ini, corak penyesuai telah dibuat. Ia membantu objek dengan antara muka yang tidak serasi untuk berfungsi bersama. Mari lihat cara menggunakannya!

Lebih lanjut mengenai masalah tersebut

Pertama, kita akan mensimulasikan tingkah laku sistem lama. Katakan ia menjana alasan untuk lewat ke tempat kerja atau sekolah. Untuk melakukan ini, ia mempunyai Excuseantara muka yang mempunyai generateExcuse(), likeExcuse()dan dislikeExcuse()kaedah.

public interface Excuse {
   String generateExcuse();
   void likeExcuse(String excuse);
   void dislikeExcuse(String excuse);
}
Kelas WorkExcusemelaksanakan antara muka 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());
Pengeluaran:

"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 melancarkan perkhidmatan menjana alasan, mengumpul statistik dan menyedari bahawa kebanyakan pengguna anda adalah pelajar universiti. Untuk melayani kumpulan ini dengan lebih baik, anda meminta pembangun lain untuk mencipta sistem yang menjana alasan khusus untuk pelajar universiti. Pasukan pembangunan menjalankan penyelidikan pasaran, meletakkan alasan, menghubungkan beberapa kecerdasan buatan, dan menyepadukan perkhidmatan dengan laporan trafik, laporan cuaca dan sebagainya. Kini anda mempunyai perpustakaan untuk menjana alasan untuk pelajar universiti, tetapi ia mempunyai antara muka yang berbeza: StudentExcuse.

public interface StudentExcuse {
   String generateExcuse();
   void dislikeExcuse(String excuse);
}
Antara muka ini mempunyai dua kaedah: generateExcuse, yang menjana alasan, dan dislikeExcuse, yang menghalang alasan daripada muncul semula pada masa hadapan. Pustaka pihak ketiga tidak boleh diedit, iaitu anda tidak boleh menukar kod sumbernya. Apa yang kita ada sekarang ialah sistem dengan dua kelas yang melaksanakan Excuseantara muka, dan perpustakaan dengan SuperStudentExcusekelas yang melaksanakan StudentExcuseantara muka:

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
   }
}
Kod tidak boleh ditukar. Hierarki kelas semasa kelihatan seperti ini: Apakah masalah yang diselesaikan oleh corak reka bentuk penyesuai?  - 2Versi sistem ini hanya berfungsi dengan antara muka Excuse. Anda tidak boleh menulis semula kod: dalam aplikasi yang besar, membuat perubahan sedemikian boleh menjadi proses yang panjang atau memecahkan logik aplikasi. Kita boleh memperkenalkan antara muka asas dan mengembangkan hierarki: Apakah masalah yang diselesaikan oleh corak reka bentuk penyesuai?  - 3Untuk melakukan ini, kita perlu menamakan semula Excuseantara muka. Tetapi hierarki tambahan adalah tidak diingini dalam aplikasi yang serius: memperkenalkan elemen akar biasa memecahkan seni bina. Anda harus melaksanakan kelas perantaraan yang membolehkan kami menggunakan kedua-dua fungsi baharu dan lama dengan kerugian yang minimum. Pendek kata, anda memerlukan penyesuai .

Prinsip di sebalik corak penyesuai

Penyesuai ialah objek perantaraan yang membolehkan kaedah panggilan satu objek difahami oleh yang lain. Mari kita laksanakan penyesuai untuk contoh kita dan panggilnya Middleware. Penyesuai kami mesti melaksanakan antara muka yang serasi dengan salah satu objek. Biarlah Excuse. Ini membolehkan Middlewareuntuk memanggil kaedah objek pertama. Middlewaremenerima panggilan dan memajukannya dengan cara yang serasi ke objek kedua. Berikut ialah Middlewarepelaksanaan dengan kaedah generateExcusedan 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
}
Ujian (dalam kod 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
   }
}
Pengeluaran:

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 yang luar biasa disesuaikan dengan keadaan cuaca semasa, kesesakan lalu lintas atau kelewatan dalam jadual pengangkutan awam. Kaedah ini generateExcusehanya menghantar panggilan ke objek lain, tanpa sebarang perubahan tambahan. Kaedah tersebut dislikeExcusememerlukan kami menyenaraihitamkan dahulu alasan tersebut. Keupayaan untuk melakukan pemprosesan data perantaraan adalah sebab mengapa orang menyukai corak penyesuai. Tetapi bagaimana pula dengan likeExcusekaedah, yang merupakan sebahagian daripada Excuseantara muka tetapi bukan sebahagian daripada StudentExcuseantara muka? Fungsi baharu tidak menyokong operasi ini. The UnsupportedOperationExceptiontelah dicipta untuk keadaan ini. Ia dilemparkan jika operasi yang diminta tidak disokong. Jom guna. Beginilah Middlewarerupa pelaksanaan baharu 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.
   }
}
Pada pandangan pertama, penyelesaian ini nampaknya tidak begitu baik, tetapi meniru fungsi boleh merumitkan keadaan. Jika pelanggan memberi perhatian, dan penyesuai didokumenkan dengan baik, penyelesaian sedemikian boleh diterima.

Bila hendak menggunakan penyesuai

  1. Apabila anda perlu menggunakan kelas pihak ketiga, tetapi antara mukanya tidak serasi dengan aplikasi utama. Contoh di atas menunjukkan cara membuat objek penyesuai yang membungkus panggilan dalam format yang boleh difahami oleh objek sasaran.

  2. Apabila beberapa subkelas sedia ada memerlukan beberapa fungsi biasa. Daripada mencipta subkelas tambahan (yang akan membawa kepada pertindihan kod), lebih baik menggunakan penyesuai.

Kelebihan dan kekurangan

Kelebihan: Penyesuai menyembunyikan daripada pelanggan butiran pemprosesan permintaan dari satu objek ke objek lain. Kod pelanggan tidak memikirkan tentang memformat data atau mengendalikan panggilan ke kaedah sasaran. Ia terlalu rumit, dan pengaturcara malas :) Kelemahan: Pangkalan kod projek adalah rumit oleh kelas tambahan. Jika anda mempunyai banyak antara muka yang tidak serasi, bilangan kelas tambahan boleh menjadi tidak terurus.

Jangan mengelirukan penyesuai dengan fasad atau penghias

Dengan hanya pemeriksaan cetek, penyesuai boleh dikelirukan dengan fasad dan corak penghias. Perbezaan antara penyesuai dan fasad ialah fasad memperkenalkan antara muka baharu dan membungkus keseluruhan subsistem. Dan penghias, tidak seperti penyesuai, menukar objek itu sendiri dan bukannya antara muka.

Algoritma langkah demi langkah

  1. Pertama, pastikan anda mempunyai masalah yang boleh diselesaikan oleh corak ini.

  2. Tentukan antara muka klien yang akan digunakan untuk berinteraksi secara tidak langsung dengan objek yang tidak serasi.

  3. Jadikan kelas penyesuai mewarisi antara muka yang ditakrifkan dalam langkah sebelumnya.

  4. Dalam kelas penyesuai, cipta medan untuk menyimpan rujukan kepada objek adaptee. Rujukan ini dihantar kepada pembina.

  5. Laksanakan semua kaedah antara muka klien dalam penyesuai. Sesuatu kaedah boleh:

    • Hantarkan panggilan tanpa membuat sebarang perubahan

    • Ubah suai atau tambah data, tambah/kurangkan bilangan panggilan ke kaedah sasaran, dsb.

    • Dalam kes yang melampau, jika kaedah tertentu tetap tidak serasi, buang UnsupportedOperationException. Operasi yang tidak disokong mesti didokumenkan dengan ketat.

  6. Jika aplikasi hanya menggunakan kelas penyesuai melalui antara muka klien (seperti dalam contoh di atas), maka penyesuai boleh dikembangkan tanpa rasa sakit pada masa hadapan.

Sudah tentu, corak reka bentuk ini bukan ubat penawar untuk semua penyakit, tetapi ia boleh membantu anda menyelesaikan masalah ketidakserasian antara objek dengan antara muka yang berbeza secara elegan. Pembangun yang mengetahui corak asas adalah beberapa langkah di hadapan mereka yang hanya tahu cara menulis algoritma, kerana corak reka bentuk diperlukan untuk mencipta aplikasi yang serius. Penggunaan semula kod tidak begitu sukar dan penyelenggaraan menjadi menyeronokkan. Itu sahaja untuk hari ini! Tetapi kami akan terus mengenali pelbagai corak reka bentuk tidak lama lagi :)
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION