Lebih lanjut tentang masalahnya
Pertama, kami akan mensimulasikan perilaku sistem lama. Misalkan itu menghasilkan alasan untuk terlambat bekerja atau sekolah. Untuk melakukan ini, ia memilikiExcuse
antarmuka yang memiliki generateExcuse()
, likeExcuse()
dan dislikeExcuse()
metode.
public interface Excuse {
String generateExcuse();
void likeExcuse(String excuse);
void dislikeExcuse(String excuse);
}
Kelas WorkExcuse
mengimplementasikan 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 SuperStudentExcuse
kelas yang mengimplementasikan StudentExcuse
antarmuka:
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: Versi 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: Untuk melakukan ini, kami harus mengganti nama Excuse
antarmuka. 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 namaMiddleware
. Adaptor kami harus mengimplementasikan antarmuka yang kompatibel dengan salah satu objek. Biarlah Excuse
. Ini memungkinkan Middleware
untuk memanggil metode objek pertama. Middleware
menerima panggilan dan meneruskannya dengan cara yang kompatibel ke objek kedua. Berikut implementasi Middleware
dengan metode generateExcuse
and 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 generateExcuse
hanya meneruskan panggilan ke objek lain, tanpa perubahan tambahan. Metode tersebut dislikeExcuse
mengharuskan 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 likeExcuse
metodenya, yang merupakan bagian dari Excuse
antarmuka tetapi bukan bagian dari StudentExcuse
antarmuka? Fungsionalitas baru tidak mendukung operasi ini. Itu UnsupportedOperationException
diciptakan untuk situasi ini. Dilempar jika operasi yang diminta tidak didukung. Mari kita gunakan. Beginilah Middleware
tampilan 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
-
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.
-
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
-
Pertama, pastikan Anda memiliki masalah yang dapat dipecahkan oleh pola ini.
-
Tentukan antarmuka klien yang akan digunakan untuk berinteraksi secara tidak langsung dengan objek yang tidak kompatibel.
-
Jadikan kelas adaptor mewarisi antarmuka yang ditentukan pada langkah sebelumnya.
-
Di kelas adaptor, buat bidang untuk menyimpan referensi ke objek yang diadaptasi. Referensi ini diteruskan ke konstruktor.
-
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.
-
-
Jika aplikasi hanya menggunakan kelas adaptor melalui antarmuka klien (seperti pada contoh di atas), maka adaptor dapat diperluas tanpa rasa sakit di masa mendatang.
GO TO FULL VERSION