using System; using System.Collections.Generic; using System.Linq; using System.Threading;
namespaceRefactoringGuru.DesignPatterns.Memento.Conceptual { // The Originator holds some important state that may change over time. It // also defines a method for saving the state inside a memento and another // method for restoring the state from it. classOriginator { // For the sake of simplicity, the originator's state is stored inside a // single variable. privatestring _state;
publicOriginator(string state) { this._state = state; Console.WriteLine("Originator: My initial state is: " + state); }
// The Originator's business logic may affect its internal state. // Therefore, the client should backup the state before launching // methods of the business logic via the save() method. publicvoidDoSomething() { Console.WriteLine("Originator: I'm doing something important."); this._state = this.GenerateRandomString(30); Console.WriteLine($"Originator: and my state has changed to: {_state}"); }
while (length > 0) { result += allowedSymbols[new Random().Next(0, allowedSymbols.Length)];
Thread.Sleep(12);
length--; }
return result; }
// Saves the current state inside a memento. public IMemento Save() { returnnew ConcreteMemento(this._state); }
// Restores the Originator's state from a memento object. publicvoidRestore(IMemento memento) { if (!(memento is ConcreteMemento)) { thrownew Exception("Unknown memento class " + memento.ToString()); }
this._state = memento.GetState(); Console.Write($"Originator: My state has changed to: {_state}"); } }
// The Memento interface provides a way to retrieve the memento's metadata, // such as creation date or name. However, it doesn't expose the // Originator's state. publicinterfaceIMemento { stringGetName();
stringGetState();
DateTime GetDate(); }
// The Concrete Memento contains the infrastructure for storing the // Originator's state. classConcreteMemento : IMemento { privatestring _state;
// The Originator uses this method when restoring its state. publicstringGetState() { returnthis._state; } // The rest of the methods are used by the Caretaker to display // metadata. publicstringGetName() { return$"{this._date} / ({this._state.Substring(0, 9)})..."; }
public DateTime GetDate() { returnthis._date; } }
// The Caretaker doesn't depend on the Concrete Memento class. Therefore, it // doesn't have access to the originator's state, stored inside the memento. // It works with all mementos via the base Memento interface. classCaretaker { private List<IMemento> _mementos = new List<IMemento>();
Originator: My initial state is: Super-duper-super-puper-super.
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: oGyQIIatlDDWNgYYqJATTmdwnnGZQj
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: jBtMDDWogzzRJbTTmEwOOhZrjjBULe
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: exoHyyRkbuuNEXOhhArKccUmexPPHZ
Caretaker: Here's the list of mementos: 12.06.2018 15:52:45 / (Super-dup...) 12.06.2018 15:52:46 / (oGyQIIatl...) 12.06.2018 15:52:46 / (jBtMDDWog...)
Client: Now, let's rollback!
Caretaker: Restoring state to: 12.06.2018 15:52:46 / (jBtMDDWog...) Originator: My state has changed to: jBtMDDWogzzRJbTTmEwOOhZrjjBULe
Client: Once more!
Caretaker: Restoring state to: 12.06.2018 15:52:46 / (oGyQIIatl...) Originator: My state has changed to: oGyQIIatlDDWNgYYqJATTmdwnnGZQj
在 C++ 中使用模式
复杂度: ★★★
流行度: ★☆☆
使用示例: 备忘录的基本功能可用序列化来实现, 这在 C++ 语言中很常见。 尽管备忘录不是生成对象状态快照的唯一或最有效的方法, 但它能在保护原始对象的结构不暴露给其他对象的情况下保存对象状态的备份。
/** * The Memento interface provides a way to retrieve the memento's metadata, such * as creation date or name. However, it doesn't expose the Originator's state. */ classMemento { public: virtual std::string GetName()const= 0; virtual std::string date()const= 0; virtual std::string state()const= 0; };
/** * The Concrete Memento contains the infrastructure for storing the Originator's * state. */ classConcreteMemento : public Memento { private: std::string state_; std::string date_;
public: ConcreteMemento(std::string state) : state_(state) { this->state_ = state; std::time_t now = std::time(0); this->date_ = std::ctime(&now); } /** * The Originator uses this method when restoring its state. */ std::string state()constoverride{ returnthis->state_; } /** * The rest of the methods are used by the Caretaker to display metadata. */ std::string GetName()constoverride{ returnthis->date_ + " / (" + this->state_.substr(0, 9) + "...)"; } std::string date()constoverride{ returnthis->date_; } };
/** * The Originator holds some important state that may change over time. It also * defines a method for saving the state inside a memento and another method for * restoring the state from it. */ classOriginator { /** * @var string For the sake of simplicity, the originator's state is stored * inside a single variable. */ private: std::string state_;
std::string random_string; for (int i = 0; i < length; i++) { random_string += alphanum[std::rand() % stringLength]; } return random_string; }
public: Originator(std::string state) : state_(state) { std::cout << "Originator: My initial state is: " << this->state_ << "\n"; } /** * The Originator's business logic may affect its internal state. Therefore, * the client should backup the state before launching methods of the business * logic via the save() method. */ voidDoSomething(){ std::cout << "Originator: I'm doing something important.\n"; this->state_ = this->GenerateRandomString(30); std::cout << "Originator: and my state has changed to: " << this->state_ << "\n"; }
/** * Saves the current state inside a memento. */ Memento *Save(){ returnnewConcreteMemento(this->state_); } /** * Restores the Originator's state from a memento object. */ voidRestore(Memento *memento){ this->state_ = memento->state(); std::cout << "Originator: My state has changed to: " << this->state_ << "\n"; } };
/** * The Caretaker doesn't depend on the Concrete Memento class. Therefore, it * doesn't have access to the originator's state, stored inside the memento. It * works with all mementos via the base Memento interface. */ classCaretaker { /** * @var Memento[] */ private: std::vector<Memento *> mementos_;
Originator: My initial state is: Super-duper-super-puper-super.
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: uOInE8wmckHYPwZS7PtUTwuwZfCIbz
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: te6RGmykRpbqaWo5MEwjji1fpM1t5D
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: hX5xWDVljcQ9ydD7StUfbBt5Z7pcSN
Caretaker: Here's the list of mementos: Sat Oct 19 18:09:37 2019 / (Super-dup...) Sat Oct 19 18:09:37 2019 / (uOInE8wmc...) Sat Oct 19 18:09:37 2019 / (te6RGmykR...)
Client: Now, let's rollback!
Caretaker: Restoring state to: Sat Oct 19 18:09:37 2019 / (te6RGmykR...) Originator: My state has changed to: te6RGmykRpbqaWo5MEwjji1fpM1t5D
Client: Once more!
Caretaker: Restoring state to: Sat Oct 19 18:09:37 2019 / (uOInE8wmc...) Originator: My state has changed to: uOInE8wmckHYPwZS7PtUTwuwZfCIbz
/** * The Originator holds some important state that may change over time. It also * defines a method for saving the state inside a memento and another method for * restoring the state from it. */ classOriginator { /** * @var string For the sake of simplicity, the originator's state is stored * inside a single variable. */ private$state;
publicfunction__construct(string$state) { $this->state = $state; echo"Originator: My initial state is: {$this->state}\n"; }
/** * The Originator's business logic may affect its internal state. Therefore, * the client should backup the state before launching methods of the * business logic via the save() method. */ publicfunctiondoSomething(): void { echo"Originator: I'm doing something important.\n"; $this->state = $this->generateRandomString(30); echo"Originator: and my state has changed to: {$this->state}\n"; }
/** * Saves the current state inside a memento. */ publicfunctionsave(): Memento { returnnewConcreteMemento($this->state); }
/** * Restores the Originator's state from a memento object. */ publicfunctionrestore(Memento $memento): void { $this->state = $memento->getState(); echo"Originator: My state has changed to: {$this->state}\n"; } }
/** * The Memento interface provides a way to retrieve the memento's metadata, such * as creation date or name. However, it doesn't expose the Originator's state. */ interfaceMemento { publicfunctiongetName(): string;
publicfunctiongetDate(): string; }
/** * The Concrete Memento contains the infrastructure for storing the Originator's * state. */ classConcreteMementoimplementsMemento { private$state;
/** * The Originator uses this method when restoring its state. */ publicfunctiongetState(): string { return$this->state; }
/** * The rest of the methods are used by the Caretaker to display metadata. */ publicfunctiongetName(): string { return$this->date . " / (" . substr($this->state, 0, 9) . "...)"; }
/** * The Caretaker doesn't depend on the Concrete Memento class. Therefore, it * doesn't have access to the originator's state, stored inside the memento. It * works with all mementos via the base Memento interface. */ classCaretaker { /** * @var Memento[] */ private$mementos = [];
Originator: My initial state is: Super-duper-super-puper-super.
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: srGIngezAEboNPDjBkuvymJKUtMSFX
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: UwCZQaHJOiERLlchyVuMbXNtpqTgWF
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: incqsdoJXkbDUuVOvRFYyKBgfzwZCQ
Caretaker: Here's the list of mementos: 2018-06-04 14:50:39 / (Super-dup...) 2018-06-04 14:50:39 / (srGIngezA...) 2018-06-04 14:50:39 / (UwCZQaHJO...)
Client: Now, let's rollback!
Caretaker: Restoring state to: 2018-06-04 14:50:39 / (UwCZQaHJO...) Originator: My state has changed to: UwCZQaHJOiERLlchyVuMbXNtpqTgWF
Client: Once more!
Caretaker: Restoring state to: 2018-06-04 14:50:39 / (srGIngezA...) Originator: My state has changed to: srGIngezAEboNPDjBkuvymJKUtMSFX
from __future__ import annotations from abc import ABC, abstractmethod from datetime import datetime from random import sample from string import ascii_letters, digits
classOriginator(): """ The Originator holds some important state that may change over time. It also defines a method for saving the state inside a memento and another method for restoring the state from it. """
_state = None """ For the sake of simplicity, the originator's state is stored inside a single variable. """
def__init__(self, state: str) -> None: self._state = state print(f"Originator: My initial state is: {self._state}")
defdo_something(self) -> None: """ The Originator's business logic may affect its internal state. Therefore, the client should backup the state before launching methods of the business logic via the save() method. """
print("Originator: I'm doing something important.") self._state = self._generate_random_string(30) print(f"Originator: and my state has changed to: {self._state}")
def_generate_random_string(self, length: int = 10) -> None: return"".join(sample(ascii_letters, length))
defsave(self) -> Memento: """ Saves the current state inside a memento. """
return ConcreteMemento(self._state)
defrestore(self, memento: Memento) -> None: """ Restores the Originator's state from a memento object. """
self._state = memento.get_state() print(f"Originator: My state has changed to: {self._state}")
classMemento(ABC): """ The Memento interface provides a way to retrieve the memento's metadata, such as creation date or name. However, it doesn't expose the Originator's state. """
defget_state(self) -> str: """ The Originator uses this method when restoring its state. """ return self._state
defget_name(self) -> str: """ The rest of the methods are used by the Caretaker to display metadata. """
returnf"{self._date} / ({self._state[0:9]}...)"
defget_date(self) -> str: return self._date
classCaretaker(): """ The Caretaker doesn't depend on the Concrete Memento class. Therefore, it doesn't have access to the originator's state, stored inside the memento. It works with all mementos via the base Memento interface. """
Originator: My initial state is: Super-duper-super-puper-super.
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: wQAehHYOqVSlpEXjyIcgobrxsZUnat
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: lHxNORKcsgMWYnJqoXjVCbQLEIeiSp
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: cvIYsRilNOtwynaKdEZpDCQkFAXVMf
Caretaker: Here's the list of mementos: 2019-01-26 21:11:24 / (Super-dup...) 2019-01-26 21:11:24 / (wQAehHYOq...) 2019-01-26 21:11:24 / (lHxNORKcs...)
Client: Now, let's rollback!
Caretaker: Restoring state to: 2019-01-26 21:11:24 / (lHxNORKcs...) Originator: My state has changed to: lHxNORKcsgMWYnJqoXjVCbQLEIeiSp
Client: Once more!
Caretaker: Restoring state to: 2019-01-26 21:11:24 / (wQAehHYOq...) Originator: My state has changed to: wQAehHYOqVSlpEXjyIcgobrxsZUnat
# The Originator holds some important state that may change over time. It also # defines a method for saving the state inside a memento and another method for # restoring the state from it. classOriginator # For the sake of simplicity, the originator's state is stored inside a single # variable. attr_accessor:state private :state
# @param [String] state definitialize(state) @state = state puts "Originator: My initial state is: #{@state}" end
# The Originator's business logic may affect its internal state. Therefore, # the client should backup the state before launching methods of the business # logic via the save() method. defdo_something puts 'Originator: I\'m doing something important.' @state = generate_random_string(30) puts "Originator: and my state has changed to: #{@state}" end
# Saves the current state inside a memento. defsave ConcreteMemento.new(@state) end
# Restores the Originator's state from a memento object. defrestore(memento) @state = memento.state puts "Originator: My state has changed to: #{@state}" end end
# The Memento interface provides a way to retrieve the memento's metadata, such # as creation date or name. However, it doesn't expose the Originator's state. classMemento # @abstract # # @return [String] defname raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end
# @abstract # # @return [String] defdate raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end
classConcreteMemento < Memento # @param [String] state definitialize(state) @state = state @date = Time.now.strftime('%F %T') end
# The Originator uses this method when restoring its state. attr_reader:state
# The rest of the methods are used by the Caretaker to display metadata. defname "#{@date} / (#{@state[0, 9]}...)" end
# @return [String] attr_reader:date end
# The Caretaker doesn't depend on the Concrete Memento class. Therefore, it # doesn't have access to the originator's state, stored inside the memento. It # works with all mementos via the base Memento interface. classCaretaker # @param [Originator] originator definitialize(originator) @mementos = [] @originator = originator end
defbackup puts "\nCaretaker: Saving Originator's state..." @mementos << @originator.save end
defundo returnif@mementos.empty?
memento = @mementos.pop puts "Caretaker: Restoring state to: #{memento.name}"
begin @originator.restore(memento) rescue StandardError undo end end
defshow_history puts 'Caretaker: Here\'s the list of mementos:'
@mementos.each { |memento| puts memento.name } end end
Originator: My initial state is: Super-duper-super-puper-super.
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: BFDECxFORrlPIMDCDfQuRwHcuvpbTv
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: xjyrOYzoBYIPYHhGKlvbQrsRvKSRzY
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: xHfPozLWyhsamFVUUPfhIaGBhaBBvK
Caretaker: Here's the list of mementos: 2019-03-06 23:04:13 / (Super-dup...) 2019-03-06 23:04:13 / (BFDECxFOR...) 2019-03-06 23:04:13 / (xjyrOYzoB...)
Client: Now, let's rollback! Caretaker: Restoring state to: 2019-03-06 23:04:13 / (xjyrOYzoB...) Originator: My state has changed to: xjyrOYzoBYIPYHhGKlvbQrsRvKSRzY
Client: Once more! Caretaker: Restoring state to: 2019-03-06 23:04:13 / (BFDECxFOR...) Originator: My state has changed to: BFDECxFORrlPIMDCDfQuRwHcuvpbTv
在 Swift 中使用模式
复杂度: ★★★
流行度: ★☆☆
使用示例: 备忘录的基本功能可用序列化来实现, 这在 Swift 语言中很常见。 尽管备忘录不是生成对象状态快照的唯一或最有效的方法, 但它能在保护原始对象的结构不暴露给其他对象的情况下保存对象状态的备份。
/// The Originator holds some important state that may change over time. It also /// defines a method for saving the state inside a memento and another method /// for restoring the state from it. classOriginator {
/// For the sake of simplicity, the originator's state is stored inside a /// single variable. privatevar state: String
init(state: String) { self.state = state print("Originator: My initial state is: \(state)") }
/// The Originator's business logic may affect its internal state. /// Therefore, the client should backup the state before launching methods /// of the business logic via the save() method. funcdoSomething() { print("Originator: I'm doing something important.") state = generateRandomString() print("Originator: and my state has changed to: \(state)") }
/// Saves the current state inside a memento. funcsave() -> Memento { returnConcreteMemento(state: state) }
/// Restores the Originator's state from a memento object. funcrestore(memento: Memento) { guardlet memento = memento as?ConcreteMementoelse { return } self.state = memento.state print("Originator: My state has changed to: \(state)") } }
/// The Memento interface provides a way to retrieve the memento's metadata, /// such as creation date or name. However, it doesn't expose the Originator's /// state. protocolMemento {
var name: String { get } var date: Date { get } }
/// The Concrete Memento contains the infrastructure for storing the /// Originator's state. classConcreteMemento: Memento {
/// The Originator uses this method when restoring its state. private(set)var state: String private(set)var date: Date
init(state: String) { self.state = state self.date =Date() }
/// The rest of the methods are used by the Caretaker to display metadata. var name: String { return state +" "+ date.description.suffix(14).prefix(8) } }
/// The Caretaker doesn't depend on the Concrete Memento class. Therefore, it /// doesn't have access to the originator's state, stored inside the memento. It /// works with all mementos via the base Memento interface. classCaretaker {
/// State and Command are often used together when the previous state of the /// object should be restored in case of failure of some operation. /// /// Note: UndoManager can be used as an alternative.
functest() {
let textView =UITextView() let undoStack =UndoStack(textView)
text = textViewMemento.text textColor = textViewMemento.textColor selectedRange = textViewMemento.selectedRange }
structTextViewMemento: Memento {
let text: String let date =Date()
let textColor: UIColor? let selectedRange: NSRange
var description: String { let time =Calendar.current.dateComponents([.hour, .minute, .second, .nanosecond], from: date) let color =String(describing: textColor) return"Text: \(text)\n"+"Date: \(time.description)\n" +"Color: \(color)\n"+"Range: \(selectedRange)\n\n" } } }
/** * The Originator holds some important state that may change over time. It also * defines a method for saving the state inside a memento and another method for * restoring the state from it. */ classOriginator { /** * For the sake of simplicity, the originator's state is stored inside a * single variable. */ privatestate: string;
constructor(state: string) { this.state = state; console.log(`Originator: My initial state is: ${state}`); }
/** * The Originator's business logic may affect its internal state. Therefore, * the client should backup the state before launching methods of the * business logic via the save() method. */ publicdoSomething(): void { console.log('Originator: I\'m doing something important.'); this.state = this.generateRandomString(30); console.log(`Originator: and my state has changed to: ${this.state}`); }
privategenerateRandomString(length: number = 10): string { const charSet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
/** * Saves the current state inside a memento. */ publicsave(): Memento { returnnewConcreteMemento(this.state); }
/** * Restores the Originator's state from a memento object. */ publicrestore(memento: Memento): void { this.state = memento.getState(); console.log(`Originator: My state has changed to: ${this.state}`); } }
/** * The Memento interface provides a way to retrieve the memento's metadata, such * as creation date or name. However, it doesn't expose the Originator's state. */ interfaceMemento { getState(): string;
getName(): string;
getDate(): string; }
/** * The Concrete Memento contains the infrastructure for storing the Originator's * state. */ classConcreteMementoimplementsMemento { privatestate: string;
/** * The Originator uses this method when restoring its state. */ publicgetState(): string { returnthis.state; }
/** * The rest of the methods are used by the Caretaker to display metadata. */ publicgetName(): string { return`${this.date} / (${this.state.substr(0, 9)}...)`; }
publicgetDate(): string { returnthis.date; } }
/** * The Caretaker doesn't depend on the Concrete Memento class. Therefore, it * doesn't have access to the originator's state, stored inside the memento. It * works with all mementos via the base Memento interface. */ classCaretaker { privatemementos: Memento[] = [];
console.log(`Caretaker: Restoring state to: ${memento.getName()}`); this.originator.restore(memento); }
publicshowHistory(): void { console.log('Caretaker: Here\'s the list of mementos:'); for (const memento ofthis.mementos) { console.log(memento.getName()); } } }
Originator: My initial state is: Super-duper-super-puper-super.
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: qXqxgTcLSCeLYdcgElOghOFhPGfMxo
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: iaVCJVryJwWwbipieensfodeMSWvUY
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: oSUxsOCiZEnohBMQEjwnPWJLGnwGmy
Caretaker: Here's the list of mementos: 2019-02-17 15:14:05 / (Super-dup...) 2019-02-17 15:14:05 / (qXqxgTcLS...) 2019-02-17 15:14:05 / (iaVCJVryJ...)
Client: Now, let's rollback!
Caretaker: Restoring state to: 2019-02-17 15:14:05 / (iaVCJVryJ...) Originator: My state has changed to: iaVCJVryJwWwbipieensfodeMSWvUY
Client: Once more!
Caretaker: Restoring state to: 2019-02-17 15:14:05 / (qXqxgTcLS...) Originator: My state has changed to: qXqxgTcLSCeLYdcgElOghOFhPGfMxo