Mega Code Archive

 
Categories / Delphi / Examples
 

Implementation of the Memento Design Pattern

Title: Implementation of the Memento Design Pattern Question: How do you implement the MEMENTO Design Pattern in Delphi ? Answer: A Memento is an object that stores a snapshot of the internal state of another object - the memento's originator, according to Gamma, Helm, Johnson and Vlissides ("Design Patterns", Addision-Wesley, 1995) In the following example the originator class is a class that does some calculations named "tCalculator". The recall-class must be a friend class of the originator class in order to access the private variables that characterize the current state. In delphi you can realize this if the two classes are defined in the same unit. A concrete implementation of the Memento design pattern looks like this : tCalculator = class private ValueA,ValueB,Interval : extended; Strings : TStringList; public ... end; tCalculatorRecall = class private RefObject : tCalculator; ValueA,ValueB,Interval : extended; Strings : TStringList; public constructor Create(Calculator : tCalculator); destructor Destroy; override; end; constructor tCalculatorRecall.Create(Calculator: tCalculator); begin inherited Create; RefObject := Calculator; ValueA := RefObject.ValueA; ValueB := RefObject.ValueB; Interval := RefObject.Interval; Strings := TStringList.Create; Strings.Assign(RefObject.Strings); end; destructor tCalculatorRecall.Destroy; begin RefObject.ValueA := ValueA; RefObject.ValueB := ValueB; RefObject.Interval := Interval; RefObject.Strings.Assign(Strings); Strings.Free; inherited Destroy; end; The following lines demonstrate how to use this class : // Store state of object CalculatorRecall:=tCalculatorRecall.Create(Calculator); // Change the state of object to do some calculations Calculator.ValueA := ... Calculator.DoSomething; // Restore the original state CalculatorRecall.Destroy; Examples from the VCL for the Memento Design Pattern are tFontRecall, tPenRecall and tBrushRecall, three new available classes in Delphi 6 that are derived from TRecall. Of course you can also define your own classes in this way. If you do this, consider two important points : * Derive the originator class from TPersistent * Implement the Assign procedure Then our example looks like this : TCalculator = class(TPersistent) private ValueA,ValueB,Interval : extended; Strings : TStringList; ... public ... procedure Assign(Source: TPersistent); override; ... end; TCalculatorRecall = class(TRecall) public constructor Create(ACalculator : TCalculator); end; procedure tCalculator.Assign(Source: TPersistent); var RefObject : tCalculator; begin if Source is tCalculator then begin RefObject := Source as tCalculator; ValueA := RefObject.ValueA; ValueB := RefObject.ValueB; Interval := RefObject.Interval; ... Strings.Assign(RefObject.Strings); ... end else inherited Assign(Source); end; constructor TCalculatorRecall.Create(ACalculator: TCalculator); begin inherited Create(TCalculator.Create, ACalculator); end;