1. Definisi mode pengamat:
Mode pengamat juga disebut mode penerbitan berlangganan, di mana suatu objek target mengelola semua objek pengamat yang bergantung padanya dan secara aktif mengeluarkan pemberitahuan ketika status berubah. Ini biasanya dicapai dengan memanggil metode masing -masing pengamat. Pola ini biasanya digunakan dalam sistem pemrosesan acara.
1. Struktur umum pola pengamat
Pertama, mari kita lihat deskripsi diagram kelas dari pola pengamat:
Peran mode pengamat adalah sebagai berikut:
Subjek (Antarmuka Topik Abstrak): Menentukan serangkaian operasi pada daftar pengamat di kelas tema, termasuk penambahan, penghapusan, pemberitahuan, dll.
Subjek konkret (kelas topik tertentu):
Pengamat (Antarmuka Pengamat Abstrak): Menentukan pengamat untuk menerima operasi pada status pembaruan kelas topik.
ConcreteObServer (Kelas Pengamat Spesifik): Menerapkan logika seperti pembaruan pemberitahuan kelas topik oleh antarmuka pengamat.
Dari diagram kelas ini, kita dapat melihat bahwa kelas tema memelihara daftar kelas yang mengimplementasikan antarmuka pengamat. Kelas tema menggunakan daftar ini untuk melakukan serangkaian penambahan, penghapusan, dan modifikasi pada pengamat. Kelas pengamat juga dapat secara aktif memanggil metode pembaruan untuk memahami informasi pembaruan status kelas tema.
Diagram kelas di atas hanya menggambarkan ide pola pengamat dasar, dan ada banyak kekurangan. Misalnya, sebagai pengamat, Anda juga dapat secara aktif berlangganan topik tertentu, dll. Contoh -contoh berikut akan membuat beberapa perubahan untuk menerapkan logika bisnis tertentu.
2. Contoh mode pengamat
Kami membangun kelas pengamat dan topik, di mana pengamat dapat secara aktif berlangganan atau membatalkan topik. Kategori tema dikelola secara seragam oleh manajer tema. Berikut ini adalah diagram kelas:
Subjek:
subjek antarmuka publik {// Daftarkan register public void pengamat (Observer Observer); // Lepaskan pengamat public void hapus (pengamat pengamat); // beri tahu semua pengamat public void notifyoBserver (); // Dapatkan pesan yang akan diterbitkan oleh kelas topik string publik getMessage ();} concerteSubject: kelas publik mysubject mengimplementasikan subjek {daftar pribadi <Bawak> pengamat; Boolean pribadi berubah; pesan string pribadi; // Kunci Objek, Digunakan untuk secara sinkron memperbarui Daftar Pengamat Private Final Object Mutex = Objek Baru (); public mysubject () {Observer = new ArrayList <Bawasi> (); berubah = false; } @Override public void register (pengamat pengamat) {if (pengamat == null) lempar nullpointerException baru (); // Bersertifikat untuk tidak mengulangi jika (! Observer.contains (pengamat)) pengamat. } @Override public void RemeT (Observer Observer) {Observer.Remove (Observer); } @Override public void notifyoBserver () {// daftar daftar temp <dermation> tempobserver = null; disinkronkan (mutex) {if (! ubah) kembali; tempobserver = new arraylist <> (this.observer); this.changed = false; } untuk (pengamat obj: tempobserver) {obj.update (); }} // kelas tema menerbitkan pesan baru public void makeChanged (string message) {System.out.println ("Subjek membuat perubahan:" + pesan); this.message = pesan; this.changed = true; notifyoBserver (); } @Override Public String getMessage () {return this.message; }}Ketika ConcertEsubject membuat pembaruan, semua pengamat dalam daftar diberitahu, dan metode pembaruan pengamat dipanggil untuk mengimplementasikan logika setelah menerima pemberitahuan. Perhatikan blok sinkronisasi di NotifyoBserver di sini. Dalam kasus multi-threading, untuk menghindari menambahkan dan menghapus daftar pengamat oleh utas lain saat menerbitkan pemberitahuan di kelas topik, daftar sementara digunakan dalam blok sinkronisasi untuk mendapatkan daftar pengamat saat ini.
Manajemen Subject: Manajer Kelas Tema
Public Class SubjectManagement {// A Record Name - Peta Private Map <String, Subject> Subject = New HashMap <String, Subject> (); public void addSubject (nama string, subjek subjek) {subjekList.put (name, subjek); } public void addSubject (subjek subjek) {subjekList.put (subjek.getClass (). getName (), subjek); } subjek publik getSubject (string subjekName) {return SubjectList.get (SubjectName); } public void RemoveSubject (nama string, subjek subjek) {} public void removeSubject (subjek subjek) {} // singleton private subjectManagement () {} public static subjectanagement getInstance () {return SubjectManagementInstance.instance; } private static class SubjechanagementInstance {static final subjectanagement instance = new SubjectManagement (); }}Tujuan dari manajer topik adalah untuk mendapatkan objek instance dari topik ketika pengamat berlangganan suatu topik.
Pengamat:
Public Interface Observer {public void update (); public void setsubject (subjek subjek);} concerteobserver: kelas publik myobserver mengimplementasikan pengamat {subjek pribadi subjek; // Dapatkan pesan Notify dari Consentrate Subjek @Override public void update () {string message = subjek.getMessage (); System.out.println ("Dari Subjek" + Subject.getClass (). GetName () + "Pesan:" + pesan); } @Override public void setSubject (subjek subjek) {this.subject = subjek; } // subcirbe Beberapa subjek void public berlangganan (String SubjectName) {SubjectManagement.getInstance (). GetSubject (SubjectName) .Register (this); } // Batal berlangganan public void cancelSubscribe (string subjekName) {SubjectManagement.getInstance (). GetSubject (SubjectName) .remove (this); }} Tes: Kami abstrak kelas subjek dan pengamat menjadi penulis dan pembaca
Public Class Observertest {private static mysubject writer; @Beforeclass public static void setupbeforeclass () melempar Exception {writer = new mysubject (); // Tambahkan penulis bernama Linus SubjectManagement.getInstance (). AddSubject ("Linus", Writer); } @Test public void test () {// Tentukan beberapa pembaca myobserver reader1 = myobserver baru (); Myobserver reader2 = myobserver baru (); Myobserver reader3 = myobserver baru (); reader1.setsubject (penulis); reader2.setsubject (penulis); reader3.setsubject (penulis); reader1.subscribe ("linus"); reader2.subscribe ("linus"); reader3.subscribe ("linus"); writer.makechanged ("Saya punya perubahan baru"); reader1.update (); }}Di atas adalah contoh kecil dari pola pengamat. Dapat dilihat bahwa setiap kelas topik harus mempertahankan daftar pengamat yang sesuai. Di sini, kita dapat lebih jauh abstrak berdasarkan tingkat abstrak dari topik tertentu, menempatkan pengumpulan ini ke dalam kelas abstrak untuk bersama -sama mempertahankan daftar. Tentu saja, operasi spesifik tergantung pada logika bisnis yang sebenarnya.
2. Pendengar di Servlet
Mari kita bicara tentang pendengar di Servlet, mari kita bicara tentang bentuk lain dari pola pengamat - model yang digerakkan oleh peristiwa. Seperti peran tema pola pengamat yang disebutkan di atas, model yang digerakkan oleh peristiwa mencakup sumber acara, acara spesifik, pendengar, dan pendengar khusus.
Pendengar di Servlet adalah model yang digerakkan oleh acara yang khas.
Ada satu set kelas yang digerakkan oleh acara di JDK, termasuk antarmuka pendengar terpadu dan sumber acara terpadu. Kode sumber adalah sebagai berikut:
/*** Antarmuka penandaan yang harus diperluas oleh semua antarmuka pendengar acara. * @since JDK1.1 */Public Interface EventListener {}Ini adalah antarmuka bendera, dan JDK menetapkan bahwa semua pendengar harus mewarisi antarmuka ini.
Kelas Publik EventObject mengimplementasikan java.io.serializable {private static final long serialversionuid = 5516075349620653480l; /*** Objek tempat acara awalnya terjadi. */ sumber objek transien yang dilindungi; /*** Membangun acara prototipe. * * @param Sumber objek tempat acara awalnya terjadi. * @Exception IllegalArgumentException Jika sumbernya nol. */ public eventObject (sumber objek) {if (source == null) lempar baru ilegalargumentException ("null source"); this.source = sumber; } /*** Objek tempat peristiwa awalnya terjadi. * * @return objek tempat acara awalnya terjadi. */ objek publik getSource () {sumber kembali; } /*** Mengembalikan representasi string dari EventObject ini. * * @Return A string representasi dari EventObject ini. */ public string toString () {return getClass (). getName () + "[source =" + source + "]"; }}EvenObject adalah sumber acara terpadu yang ditentukan oleh JDK. Kelas EvenObject mendefinisikan sumber acara dan metode GET untuk mendapatkan sumber acara.
Mari kita analisis proses operasi pendengar servlet.
1. Komposisi pendengar servlet
Saat ini, ada 6 jenis antarmuka pendengar untuk dua jenis peristiwa di servlets, seperti yang ditunjukkan pada gambar di bawah ini:
Situasi pemicu spesifik adalah sebagai berikut:
2. Proses pemicu pendengar tertentu
Mari kita ambil ServletRequestAttributeListener sebagai contoh untuk menganalisis proses yang digerakkan oleh peristiwa di sini.
Pertama -tama, ketika httpservletRequest memanggil metode setattrilbute, itu sebenarnya disebut org.apache.catalina.connector.request#metode setattrilbute. Mari kita lihat kode sumbernya:
public void setAttribute (nama string, nilai objek) {... // Kode logika di atas telah dihilangkan // Di sini pendengar diberitahukannyaTributeAssigned (name, value, oldvalue); }Berikut ini adalah kode sumber NotifyAttributeAssigned (nama string, nilai objek, objek oldValue)
private void notifyAttributeAssigned (nama string, nilai objek, objek oldvalue) {// Dapatkan objek instance dari pendengar yang didefinisikan dalam webapp dari pendengar objek wadah [] = context.getApplicationEventListeners (); if ((listeners == null) || (listeners.length == 0)) {return; } boolean diganti = (oldvalue! = null); // Buat Acara Terkait Objek ServletRequestAttributeEvent Event = null; if (diganti) {event = servletRequestAttributeEvent baru (context.getSerVletContext (), getRequest (), name, oldvalue); } else {event = new servletRequestAttributeEvent (context.getSerVletContext (), getRequest (), name, value); } // ketenangan melalui semua daftar pendengar dan temukan pendengar untuk acara yang sesuai untuk (int i = 0; i <listeners.length; i ++) {if (! (Pendengar [i] instance dari servletRequestAttributeListener)) {lanjutan; } // Memanggil metode pendengar untuk mengimplementasikan Operasi Mendengarkan ServletRequestAttributEnterer Listener = (servletRequestAttributeListener) pendengar [i]; coba {if (diganti) {listener.attributeReplaced (event); } else {listener.attributeadded (event); }} catch (throwable t) {exceptionutils.handlethrowable (t); context.getLogger (). error (sm.getString ("coyoterequest.attributeevent"), t); // Valve kesalahan akan mengambil pengecualian ini dan menampilkannya ke atribut pengguna.put (requestDispatcher.error_exception, t); }}}Contoh di atas dengan jelas menunjukkan bagaimana servletRequestAttributeListener disebut. Pengguna hanya perlu menerapkan antarmuka pendengar. Pendengar di Servlets hampir meliput acara yang Anda minati sepanjang seluruh siklus hidup servlet. Penggunaan pendengar ini yang fleksibel dapat membuat program lebih fleksibel.
3. Contoh komprehensif
Misalnya, jika Anda telah menonton film polisi dan gangster TVB, Anda akan tahu bagaimana keramahannya bekerja. Secara umum, seorang polisi mungkin memiliki beberapa agen penyamaran yang menyelinap ke musuh dan menanyakan informasi. Agen yang menyamar bekerja sepenuhnya pada instruksi pemimpinnya. Pemimpin mengatakan tindakan apa yang harus dia ikuti. Jika waktu tindakan berubah, ia harus segera mengubah waktu yang ia ikuti dengan tindakan tersebut. Jika pemimpin mengirim dua agen yang menyamar untuk menyerang musuh, maka pemimpinnya setara dengan tema abstrak. Inspektur Zhang San mengirim dua agen yang menyamar Li Si dan Wan Wang Wu. Zhang San setara dengan tema tertentu, dan agen yang menyamar setara dengan pengamat abstrak. Kedua agen yang menyamar ini adalah Li Si dan Wang Wu, yang merupakan pengamat khusus. Tindakan penyelidikan setara dengan pengamat yang mendaftarkan subjek. Maka diagram kelas ini adalah sebagai berikut:
Menggunakan Java API untuk mengimplementasikan deskripsi kode sebagai berikut:
pengamat paket; impor java.util.list; impor java.util.observable; impor java.util.observable; / ***Deskripsi: Polisi Zhang San*/ Polisi Kelas Publik Memperluas {Waktu String Pribadi; Polisi Publik (Daftar <WETIGNER> DAFTAR) {super (); untuk (pengamat o: daftar) {addoBserver (o); }} public void change (string time) {this.time = time; setChanged (); NotifyoBserver (this.Time); }} pengamat paket; impor java.util.observable; impor java.util.observer; / ** *Deskripsi: Undercover A */ kelas publik Undercovera mengimplementasikan pengamat {private string time; @Override public void update (Observable o, objek arg) {time = (string) arg; System.out.println ("mengungkap pesan yang diterima, dan waktu tindakannya adalah:"+waktu); }} pengamat paket; impor java.util.observable; impor java.util.observer; / ** *Deskripsi: UnderCover B */ Kelas Publik Undercoverb mengimplementasikan pengamat {private string time; @Override public void update (Observable o, objek arg) {time = (string) arg; System.out.println ("Uncover B menerima pesan, dan waktu tindakannya adalah:"+waktu); }} pengamat paket; impor java.util.arraylist; impor java.util.list; impor java.util.observer; / ***Deskripsi: tes*/ klien kelas publik {/ ***@param args*/ public static void main (string [] args) {undercovera o1 = new undercovera (); Undercoverb o2 = undercoverb baru (); Daftar <Bawak> Daftar = ArrayList baru <> (); list.add (o1); list.add (o2); Subjek Polisi = Polisi Baru (Daftar); subjek.change ("02:25"); System.out.println ("=============================================================== Advanced ============================================================================; Hasil uji coba:
Undercover B Menerima pesan, dan waktu tindakannya adalah: 02:25 menyamar A menerima pesan, dan waktu tindakannya adalah: 02:25 ================================== UNDERCOVER B Menerima pesan, dan waktu aksi adalah: 0 Nounin: 01 OVER: 01 DUNIA: 01 DUNIA: AKSI AKSI: 01.
4. Ringkasan
Pola pengamat mendefinisikan hubungan satu-ke-banyak antara objek. Ketika keadaan suatu objek (pengamat) berubah, objek yang bergantung padanya akan diberitahu. Ini dapat diterapkan untuk menerbitkan berlangganan, perubahan update dalam skenario bisnis tersebut.
Pengamat menggunakan metode kopling longgar. Pengamat tidak tahu rincian pengamat, tetapi hanya tahu bahwa pengamat telah menerapkan antarmuka.
Model yang digerakkan oleh peristiwa lebih fleksibel, tetapi juga membayar biaya kompleksitas sistem, karena kita harus menyesuaikan pendengar dan acara untuk setiap sumber acara, yang akan meningkatkan beban pada sistem.
Inti dari model pengamat adalah untuk pertama-tama membedakan peran dan memposisikan pengamat dan pengamat, dan mereka adalah hubungan banyak-ke-satu. Kunci implementasi adalah untuk membangun hubungan antara pengamat dan pengamat. Misalnya, ada set di kelas pengamat yang digunakan untuk menyimpan pengamat, dan semua pengamat harus diberitahu ketika hal yang terdeteksi berubah. Dalam konstruktor pengamat, itu akan diteruskan oleh pengamat dan juga akan mendaftarkan dirinya dalam daftar pengamat yang dimiliki oleh pengamat, yaitu, daftar pengamat.
1. Keuntungan dari mode pengamat:
(1) Tema abstrak hanya mengandalkan pengamat abstrak (2) mode pengamat mendukung komunikasi siaran (3) mode pengamat memisahkan lapisan pembuatan informasi dan lapisan respons
2. Kerugian mode pengamat:
(1) Jika suatu topik didaftarkan oleh sejumlah besar pengamat, akan dikenakan biaya lebih tinggi untuk memberi tahu semua pengamat (2) jika metode respons beberapa pengamat diblokir, seluruh proses pemberitahuan akan diblokir, dan pengamat lain tidak dapat diberitahu dalam waktu.