Definisi dan Struktur
Mode Memento juga disebut Mode Token. GOF mendefinisikan mode memo sebagai: tanpa menghancurkan enkapsulasi, menangkap keadaan internal suatu objek dan menyimpan keadaan ini di luar objek. Dengan cara ini, objek dapat dikembalikan ke keadaan yang disimpan semula nanti.
Saat berbicara tentang mode perintah, kami pernah menyebutkan bahwa menggunakan peran perintah perantara dapat mewujudkan fungsi undo dan redo. Dari definisi, kita dapat melihat bahwa mode memo secara khusus digunakan untuk menyimpan keadaan historis objek, yang sangat membantu untuk mengimplementasikan fungsi undo dan redo dengan baik. Oleh karena itu, dalam mode perintah, undo dan redo fungsi dapat diimplementasikan bersama dengan mode memo.
Faktanya, masih sangat sederhana untuk hanya menyadari fungsi menyimpan keadaan objek pada saat tertentu - menempatkan atribut yang akan disimpan dalam objek ke dalam objek yang berspesialisasi dalam manajemen cadangan, dan memanggil metode yang disepakati untuk memasukkan atribut cadangan kembali ke objek asli bila diperlukan. Tetapi Anda harus melihat dengan baik untuk memungkinkan objek cadangan Anda mengakses properti di objek asli, apakah itu berarti Anda harus mengungkapkan semua properti dari yang asli dari objek dalam paket? Jika pendekatan Anda telah merusak enkapsulasi, maka Anda harus mempertimbangkan refactoring.
Mode memorandum hanyalah solusi umum yang diusulkan oleh GOF untuk masalah "memulihkan keadaan asli suatu objek pada waktu tertentu". Oleh karena itu, dalam hal bagaimana mempertahankan enkapsulasi - karena faktor -faktor seperti karakteristik bahasa, pola memorandum tidak dijelaskan secara rinci, tetapi hanya menjelaskan ide -ide berdasarkan C ++.
1) Peran Memorandum: Peran Memorandum menyimpan status internal "Peran Inisiator Memorandum". "Peran Inisiator Memorandum" menentukan keadaan internal "peran inisiator memorandum" mana yang disimpan sesuai kebutuhan. Untuk mencegah objek lain selain "peran inisiator memorandum" mengakses memo. Memo sebenarnya memiliki dua antarmuka. "Peran Manajer Memo" hanya dapat melihat antarmuka sempit yang disediakan oleh memo - tidak terlihat untuk atribut yang disimpan dalam peran memo. "Peran Inisiator Memorandum" dapat melihat antarmuka yang luas - Anda bisa mendapatkan atribut yang Anda masukkan ke dalam peran memorandum.
2) Peran inisiasi memo (pencetus): "Peran Inisiasi Memo" menciptakan memo untuk mencatat keadaan internalnya pada saat saat ini. Gunakan memo untuk mengembalikan keadaan internal saat dibutuhkan.
3) Peran Manajer Memorandum (Penjaga): Bertanggung jawab untuk menyimpan memo. Isi memo tidak dapat dioperasikan atau diperiksa.
Diagram kelas dari mode memo sangat sederhana:
Implementasi Kode Umum
originator kelas {private string state = ""; Public String getState () {return state; } public void setState (state string) {this.state = state; } public cegnememento () {return baru memento (this.state); } public void restorememento (Memento Memento) {this.setState (kasa.getState ()); }} kelas memento {private string state = ""; kenang -kenangan publik (status string) {this.state = state; } public String getState () {return state; } public void setState (state string) {this.state = state; }} class caretaker {private memento memento; kenang -kenangan publik getmemento () {return kenang -kenangan; } public void setMemento (Mememento Memento) {this.memento = Memento; }} klien kelas publik {public static void main (string [] args) {originator originator = originator baru (); originator.setState ("Status 1"); System.out.println ("Status Awal:"+originator.getState ()); Penjaga penjaga = penjaga baru (); caretaker.setmemento (originator.createMemento ()); originator.setState ("status2"); System.out.println ("Status Setelah Mengubah:"+originator.getState ()); originator.Restorememento (caretaker.getmemento ()); System.out.println ("Status Setelah Pemulihan:"+originator.getState ()); }}Kode ini menunjukkan contoh cadangan tunggal negara bagian. Logikanya sangat sederhana: variabel status di kelas pencetus perlu dicadangkan sehingga dapat dipulihkan saat dibutuhkan; Di kelas kenang -kenangan, ada juga variabel keadaan yang digunakan untuk menyimpan keadaan sementara dari variabel keadaan di kelas originator; dan kelas penjaga digunakan untuk mengelola kelas memorandum, yang digunakan untuk menulis status atau mengambil status ke dalam objek memorandum.
Memo multi-state multi-backup
Dalam contoh demonstrasi kode umum, kelas pencetus hanya memiliki satu variabel keadaan yang perlu dicadangkan, sementara biasanya, peran inisiator biasanya adalah Javabean, ada lebih dari satu variabel yang perlu dicadangkan dalam objek, dan lebih dari satu keadaan yang perlu dicadangkan. Ini adalah memo multi-state multi-backup. Ada banyak cara untuk mengimplementasikan memo. Ada banyak deformasi dan metode pemrosesan untuk memo. Metode seperti kode umum umumnya tidak digunakan. Dalam kebanyakan kasus, memo adalah multi-state dan beberapa cadangan. Bahkan, juga sangat mudah untuk mengimplementasikan multi-state dan multi-backup. Metode yang paling umum digunakan adalah menambahkan wadah peta ke kenang -kenangan untuk menyimpan semua negara bagian, dan menggunakan wadah peta di kelas pengasuh untuk menyimpan semua cadangan. Di bawah ini kami memberikan contoh multi-state dan multi-backup:
originator kelas {private string state1 = ""; Private String State2 = ""; Private String State3 = ""; public string getState1 () {return state1; } public void setState1 (String State1) {this.state1 = state1; } public String getState2 () {return state2; } public void setState2 (String State2) {this.state2 = state2; } public String getState3 () {return state3; } public void setState3 (String State3) {this.state3 = state3; } public Memento createMemento () {return New Memento (beanutils.backupprop (this)); } public void restorememento (Memento Memento) {beanutils.RestoreProp (this, memento.getStateMap ()); } public string toString () {return "state1 ="+state1+"state2 ="+state2+"state3 ="+state3; }} class memento {private Map <String, Object> StateMap; kenang -kenangan publik (peta <string, objek> peta) {this.stateMap = peta; } peta publik <String, Object> getStateMap () {return statemap; } public void setStateMap (peta <string, object> statemap) {this.stateMap = statemap; }} class beanutils {public static Map <String, Object> backupprop (Object Bean) {MAP <String, Object> hasil = HashMap baru <String, Object> (); coba {beaninfo beaninfo = introspector.getBeanInfo (bean.getClass ()); PropertyDescriptor [] deskriptor = beanInfo.getPropertyDescriptors (); untuk (PropertyDescriptor des: descriptors) {string fieldName = des.getName (); Metode getter = des.getreadmethod (); Object fieldValue = getter.invoke (bean, objek baru [] {}); if (! fieldname.equalsignorecase ("class")) {result.put (fieldName, fieldValue); }}}} catch (Exception e) {E.PrintStackTrace (); } hasil pengembalian; } public static void restoreProp (Object Bean, Map <String, Object> PropMap) {coba {beaninfo beaninfo = introspector.getBeanInfo (bean.getClass ()); PropertyDescriptor [] deskriptor = beanInfo.getPropertyDescriptors (); untuk (PropertyDescriptor des: descriptors) {string fieldName = des.getName (); if (propmap.containskey (fieldName)) {metode setter = des.getWriteMethod (); setter.invoke (bean, objek baru [] {propmap.get (fieldName)}); }}} catch (Exception e) {e.printstacktrace (); }}} class caretaker {private Map <string, Memento> memmap = new HashMap <String, Memento> (); kenang -kenangan publik getmemento (indeks string) {return memmap.get (index); } public void setMementO (Indeks String, Memento Memento) {this.memmap.put (index, memento); }} class client {public static void main (string [] args) {originator ori = new originator (); Penjaga penjaga = penjaga baru (); ori.setState1 ("Cina"); ori.setState2 ("kuat"); ori.setState3 ("kemakmuran"); System.out.println ("=== Status Inisialisasi ===/n"+ori); caretaker.setmemento ("001", ori.createMemento ()); ori.setState1 ("software"); ori.setState2 ("struktur"); ori.setState3 ("luar biasa"); System.out.println ("=== Status yang dimodifikasi ===/n"+ori); Ori.Restorememento (Careteraker.getmemento ("001")); System.out.println ("=== Status yang Dipulihkan ===/N"+Ori); }} Keuntungan dan kerugian dari mode memorandum dan keunggulan mode memorandum untuk skenario yang berlaku adalah:
Ketika status dalam peran inisiator berubah, itu mungkin merupakan perubahan yang salah. Kita dapat mengembalikan perubahan yang salah ini menggunakan mode memo.
Status cadangan disimpan di luar peran inisiator, sehingga peran inisiator tidak perlu mengelola status setiap cadangan.
Kekurangan Mode Memo:
Dalam aplikasi yang sebenarnya, mode memorandum adalah multi-state dan multi-backup. Keadaan peran inisiator perlu disimpan dalam objek memorandum, yang mengkonsumsi sumber daya relatif parah.
Jika Anda perlu menyediakan operasi rollback, menggunakan mode memo sangat cocok, seperti operasi transaksi JDBC, pemulihan Ctrl+Z editor teks, dll.