คำจำกัดความและโครงสร้าง
โหมด Memento เรียกอีกอย่างว่าโหมดโทเค็น GOF กำหนดโหมดบันทึกเป็น: โดยไม่ทำลายการห่อหุ้มจับสถานะภายในของวัตถุและบันทึกสถานะนี้ออกไปนอกวัตถุ ด้วยวิธีนี้วัตถุสามารถกู้คืนไปยังสถานะเดิมที่บันทึกไว้ในภายหลัง
เมื่อพูดถึงโหมดคำสั่งเราเคยกล่าวถึงว่าการใช้บทบาทคำสั่งระดับกลางสามารถตระหนักถึงฟังก์ชั่นของการเลิกทำและการทำซ้ำ จากคำจำกัดความเราจะเห็นว่าโหมดบันทึกนั้นใช้โดยเฉพาะในการจัดเก็บสถานะทางประวัติศาสตร์ของวัตถุซึ่งเป็นประโยชน์อย่างมากในการใช้ฟังก์ชั่นการเลิกทำและทำซ้ำได้ดี ดังนั้นในโหมดคำสั่งฟังก์ชั่นการเลิกทำและการทำซ้ำสามารถนำไปใช้ร่วมกับโหมดบันทึก
ในความเป็นจริงมันยังคงเป็นเรื่องง่ายมากที่จะตระหนักถึงฟังก์ชั่นของการบันทึกสถานะของวัตถุในช่วงเวลาหนึ่ง - ใส่แอตทริบิวต์ที่จะบันทึกไว้ในวัตถุลงในวัตถุที่เชี่ยวชาญในการจัดการการสำรองข้อมูลและเรียกวิธีการที่ตกลงไว้เพื่อนำแอตทริบิวต์สำรองกลับเข้าไปในวัตถุดั้งเดิมเมื่อจำเป็น แต่คุณต้องดูที่ดีเพื่อให้วัตถุสำรองของคุณสามารถเข้าถึงคุณสมบัติในวัตถุต้นฉบับได้หมายความว่าคุณต้องเปิดเผยคุณสมบัติทั้งหมดของวัตถุส่วนตัวดั้งเดิมของวัตถุในแพ็คเกจหรือไม่? หากวิธีการของคุณทำลายการห่อหุ้มคุณควรพิจารณา refactoring
Memorandum Mode เป็นเพียงโซลูชันทั่วไปที่เสนอโดย GOF สำหรับปัญหาของ "การกู้คืนสถานะดั้งเดิมของวัตถุในเวลาหนึ่ง" ดังนั้นในแง่ของวิธีการรักษา encapsulation - เนื่องจากปัจจัยเช่นลักษณะภาษารูปแบบบันทึกข้อตกลงไม่ได้อธิบายอย่างละเอียด แต่จะอธิบายความคิดตาม C ++ เท่านั้น
1) บทบาทของ Memento: บทบาทของบันทึกช่วยเก็บสถานะภายในของ "บทบาทผู้ริเริ่มบันทึก" "บทบาทผู้ริเริ่มบันทึกข้อตกลง" กำหนดว่าสถานะภายในของ "บทบาทผู้ริเริ่มบันทึกข้อตกลง" จะถูกเก็บไว้ตามความจำเป็น เพื่อป้องกันวัตถุอื่น ๆ นอกเหนือจาก "บทบาทผู้ริเริ่มบันทึก" จากการเข้าถึงบันทึกช่วยจำ บันทึกช่วยจำจริงมีสองอินเทอร์เฟซ "Memo Manager บทบาท" สามารถดูอินเทอร์เฟซแคบ ๆ ที่จัดทำโดยบันทึก - มันจะมองไม่เห็นสำหรับคุณลักษณะที่เก็บไว้ในบทบาทบันทึก "บทบาทผู้ริเริ่มบันทึกข้อตกลง" สามารถดูอินเทอร์เฟซที่กว้าง - คุณสามารถรับคุณลักษณะที่คุณใส่ลงในบทบาทบันทึกข้อตกลง
2) บทบาทการเริ่มต้น (ผู้ริเริ่ม): "บทบาทการเริ่มต้นบันทึก" สร้างบันทึกช่วยจำเพื่อบันทึกสถานะภายในในขณะนี้ ใช้บันทึกช่วยจำเพื่อกู้คืนสถานะภายในเมื่อจำเป็น
3) Memorandum Manager (ผู้ดูแล) บทบาท: รับผิดชอบในการบันทึกบันทึกช่วยจำ เนื้อหาของบันทึกไม่สามารถดำเนินการหรือตรวจสอบได้
แผนภาพคลาสของโหมดบันทึกนั้นง่ายมาก:
การใช้รหัสทั่วไป
ผู้ริเริ่มคลาส {สถานะสตริงส่วนตัว = ""; สตริงสาธารณะ getState () {return state; } โมฆะสาธารณะ setState (สถานะสตริง) {this.state = state; } Public Memento CreateMemento () {ส่งคืน Memento ใหม่ (this.state); } โมฆะสาธารณะ Restorememento (Memento Memento) {this.setState (memento.getState ()); }} คลาส Memento {Private String State = ""; ของที่ระลึกสาธารณะ (สถานะสตริง) {this.state = state; } สตริงสาธารณะ getState () {return state; } โมฆะสาธารณะ setState (สถานะสตริง) {this.state = state; }} ผู้ดูแลชั้นเรียน {Private Memento Memento; Public Memento GetMemento () {return memento; } โมฆะสาธารณะ setMemento (Memento Memento) {this.memento = Memento; }} ไคลเอนต์คลาสสาธารณะ {โมฆะคงที่สาธารณะหลัก (String [] args) {ผู้สร้างผู้สร้าง = ผู้สร้างใหม่ (); ผู้ริเริ่ม. SetState ("สถานะ 1"); System.out.println ("สถานะเริ่มต้น:"+ผู้เริ่มต้น GetState ()); ผู้ดูแลผู้ดูแล = ผู้ดูแลใหม่ (); ผู้ดูแล. SetMemento (ผู้ริเริ่ม. CreateMemento ()); ผู้เริ่มต้น SetState ("Status2"); System.out.println ("สถานะหลังจากการเปลี่ยนแปลง:"+originator.getState ()); ผู้ริเริ่ม. restorememento (caretaker.getMemento ()); System.out.println ("สถานะหลังจากการกู้คืน:"+originator.getState ()); -รหัสแสดงตัวอย่างของการสำรองข้อมูลเดียวสถานะเดียว ตรรกะนั้นง่ายมาก: ตัวแปรสถานะในคลาสผู้ริเริ่มจะต้องได้รับการสำรองเพื่อให้สามารถกู้คืนได้เมื่อจำเป็น ในคลาสของ Memento นอกจากนี้ยังมีตัวแปรสถานะที่ใช้ในการจัดเก็บสถานะชั่วคราวของตัวแปรสถานะในคลาสผู้ริเริ่ม และคลาสผู้ดูแลใช้ในการจัดการคลาสบันทึกซึ่งใช้ในการเขียนสถานะหรือดึงสถานะลงในวัตถุบันทึกข้อตกลง
บันทึกมัลติแบ็คอัพหลายรัฐ
ในตัวอย่างของการสาธิตรหัสทั่วไปคลาสผู้ริเริ่มมีตัวแปรสถานะเดียวที่ต้องสำรองในขณะที่โดยปกติบทบาทผู้ริเริ่มมักจะเป็น Javabean มีตัวแปรมากกว่าหนึ่งตัวที่ต้องสำรองในวัตถุและมากกว่าหนึ่งรัฐที่ต้องได้รับการสำรอง นี่คือบันทึกหลายรัฐหลายรัฐ มีหลายวิธีในการใช้บันทึกช่วยจำ มีการเสียรูปและวิธีการประมวลผลมากมายสำหรับบันทึกช่วยจำ วิธีการเช่นรหัสทั่วไปโดยทั่วไปไม่ได้ใช้ ในกรณีส่วนใหญ่บันทึกช่วยจำเป็นหลายรัฐและการสำรองข้อมูลหลายครั้ง ในความเป็นจริงมันเป็นเรื่องง่ายมากที่จะใช้หลายรัฐและหลายแบ็คอัพ วิธีที่ใช้กันมากที่สุดคือการเพิ่มคอนเทนเนอร์แผนที่ลงใน Memento เพื่อจัดเก็บทุกรัฐและใช้คอนเทนเนอร์แผนที่ในคลาส Caretaker เพื่อจัดเก็บการสำรองข้อมูลทั้งหมด ด้านล่างเราให้ตัวอย่างของหลายรัฐและหลายแบ็คอัพ:
ผู้ริเริ่มคลาส {Private String State1 = ""; สตริงส่วนตัว state2 = ""; สตริงส่วนตัว state3 = ""; สตริงสาธารณะ getState1 () {return state1; } โมฆะสาธารณะ setState1 (String state1) {this.state1 = state1; } สตริงสาธารณะ getState2 () {return state2; } โมฆะสาธารณะ setState2 (String state2) {this.state2 = state2; } สตริงสาธารณะ getState3 () {return state3; } โมฆะสาธารณะ setState3 (String state3) {this.state3 = state3; } Public Memento CreateMemento () {ส่งคืน Memento ใหม่ (beanutils.backupprop (นี่)); } โมฆะสาธารณะ Restorememento (Memento Memento) {beanutils.restoreprop (นี่, memento.getStateMap ()); } สตริงสาธารณะ toString () {return "state1 ="+state1+"state2 ="+state2+"state3 ="+state3; }} คลาส Memento {แผนที่ส่วนตัว <สตริงวัตถุ> Statemap; Public Memento (แผนที่ <String, Object> MAP) {this.stateMap = MAP; } แผนที่สาธารณะ <สตริงวัตถุ> getStateMap () {return statemap; } โมฆะสาธารณะ setStateMap (แผนที่ <string, object> statemap) {this.stateMap = statemap; }} คลาส beanutils {แผนที่สาธารณะคงที่ <String, Object> backupprop (Object Bean) {Map <String, Object> result = new HashMap <String, Object> (); ลอง {beaninfo beaninfo = introspector.getBeanInfo (bean.getClass ()); PropertyDescriptor [] descriptors = beaninfo.getPropertyDescriptors (); สำหรับ (PropertyDescriptor des: descriptors) {String fieldName = des.getName (); วิธี getter = des.getReadMethod (); Object FieldValue = getter.invoke (ถั่ว, วัตถุใหม่ [] {}); if (! fieldName.equalsignorecase ("คลาส")) {result.put (fieldName, fieldValue); }}}} catch (Exception E) {E.printStackTrace (); } ผลตอบแทนผลลัพธ์; } โมฆะคงที่สาธารณะ restoreprop (Object Bean, MAP <String, Object> Propmap) {ลอง {beaninfo beaninfo = introspector.getBeanInfo (bean.getClass ()); PropertyDescriptor [] descriptors = beaninfo.getPropertyDescriptors (); สำหรับ (PropertyDescriptor des: descriptors) {String fieldName = des.getName (); if (propmap.containskey (fieldName)) {method setter = des.getWriteMethod (); setter.invoke (ถั่ว, วัตถุใหม่ [] {propmap.get (fieldName)}); }}} catch (exception e) {e.printstacktrace (); }}} ผู้ดูแลชั้นเรียน {แผนที่ส่วนตัว <สตริง, memento> memmap = new hashmap <string, memento> (); Public Memento GetMemento (ดัชนีสตริง) {return memmap.get (ดัชนี); } โมฆะสาธารณะ setMemento (ดัชนีสตริง, Memento Memento) {this.memmap.put (ดัชนี, Memento); }} ไคลเอนต์คลาส {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {ผู้สร้าง Ori = ใหม่ผู้สร้างใหม่ (); ผู้ดูแลผู้ดูแล = ผู้ดูแลใหม่ (); ori.setstate1 ("จีน"); ori.setstate2 ("แข็งแกร่ง"); ori.setstate3 ("ความเจริญรุ่งเรือง"); System.out.println ("=== สถานะการเริ่มต้น ====/n"+ori); ผู้ดูแล. SetMemento ("001", Ori.CreateMemento ()); ori.setState1 ("ซอฟต์แวร์"); ori.setstate2 ("โครงสร้าง"); ori.setstate3 ("ยอดเยี่ยม"); System.out.println ("=== สถานะที่แก้ไข ====/n"+ori); ori.restorememento (Caretaker.getMemento ("001")); System.out.println ("=== สถานะคืนค่า ====/n"+ori); - ข้อดีและข้อเสียของโหมดบันทึกและข้อดีของโหมดบันทึกข้อตกลงสำหรับสถานการณ์ที่เกี่ยวข้องคือ:
เมื่อสถานะในการเปลี่ยนแปลงบทบาทของผู้ริเริ่มอาจเป็นการเปลี่ยนแปลงที่ผิด เราสามารถกู้คืนการเปลี่ยนแปลงที่ไม่ถูกต้องนี้โดยใช้โหมดบันทึก
สถานะของการสำรองข้อมูลจะถูกบันทึกไว้นอกบทบาทผู้ริเริ่มดังนั้นบทบาทผู้ริเริ่มไม่จำเป็นต้องจัดการสถานะของการสำรองข้อมูลแต่ละครั้ง
ข้อเสียของโหมดบันทึก:
ในแอปพลิเคชันจริงโหมดบันทึกข้อตกลงคือหลายรัฐและหลายแบ็คอัพ สถานะของบทบาทผู้ริเริ่มจะต้องเก็บไว้ในวัตถุบันทึกข้อตกลงซึ่งใช้ทรัพยากรค่อนข้างรุนแรง
หากคุณต้องการให้การดำเนินการย้อนกลับการใช้โหมดบันทึกนั้นเหมาะสมมากเช่นการดำเนินการธุรกรรม JDBC การกู้คืน Ctrl+Z ของตัวแก้ไขข้อความ ฯลฯ