AFW 4.0

Version 4.0 of AFW adds mementos to AFW 3.0. This is only a minor improvement, so bumping the version number to 4.0 might be an over doing it.

AFW Commands

The AFW 3.1 command base class is similar to the AFW 3.0 counterpart, except undo() is no longer a virtual function that must be redefined in the many derived classes:

class Command
{
public:
   virtual void execute() = 0;
   void undo();
   // etc.
protected:
   Memento* myMemento;
   // etc.
};

AFW 3.1 commands are caretakers for mementos, which are instances of classes derived from a polymorphic base class in the framework:

class Memento
{
public:
   virtual ~Memento() {}
};

Although execute() is a pure virtual function that must be redefined in derived classes, we can provide a partial implementation that deletes the old memento, then asks the model to create a new one:

void Command::execute()
{
   if (myMemento) delete myMemento;
   myMemento = theModel->makeMemento();
}

The undo() function asks the model to create a new memento. This will be used if the command needs to be redone. Next, the model is asked to restore its former state using the memento encapsulated by the command:

void Command::undo()
{
   if (myMemento && undoable)
   {
      Memento* m = theModel->makeMemento();
      theModel->restoreState(myMemento);
      delete myMemento;
      myMemento = m;
   }
}

AFW Model

AFW 3.1 models are similar to AFW 3.0 models, except for a virtual factory method for creating mementos and a virtual function that uses a memento to restore the model to its former state. Both of these functions will need to be redefined in a derived class:

class Model: public Persistent
{
public:
   virtual void restoreState(Memento* m) {};
   virtual Memento* makeMemento() { return 0; };
   // etc.
};

Customizing AFW: Brick CAD 3.1

Predictably, Brick CAD 3.1 customizes AFW 3.1. Much of the implementation is identical to Brick CAD 3.0. Of course we need to derive a class from Memento that encapsulates the non re-computable attributes of a brick. Since weight and volume can be re-computed from height, width, and length, we can get away with just storing these three attributes:

class BrickMemento: public Memento
{
   friend class Brick;
   BrickMemento(int h = 0, int w = 0, int l = 0)
   {
      oldHeight = h;
      oldWidth = w;
      oldLength = l;
   }
   int oldHeight, oldWidth, oldLength;
};

Notice that all of the BrickMemento members are private. Only bricks will be able to access this information by virtue of the friend declaration. This preserves encapsulation of model data.

Brick CAD 3.1 Models

AFW 3.1 Model-derived classes must provide implementations of the makeMemento() factory method and restoreState(). The Brick implementation of makeMemento() simply makes a new brick memento using the current

class Brick: public Model
{
public:
   void restoreState(Memento* m);
   Memento* makeMemento()
   {
      return new BrickMemento(height, width, length);
   }
   // etc.
};

The restoreState() function downcasts its memento argument to a brick memento, copies the encapsulates height, width, and length to its member variables, then re-computes volume and weight using updateProps():

void Brick::restoreState(Memento* m)
{
   BrickMemento* bm = (BrickMemento*)m;
   height = bm->oldHeight;
   width = bm->oldWidth;
   length = bm->oldLength;
   updateProps();
   modified = true;
   notify();
}

Brick CAD 3.1 Commands

AFW 3.1 command-derived classes don't need to declare or implement an undo() function:

class SetHeightCommand: public Command
{
public:
   SetHeightCommand(Brick* b = 0, int h = 5); // as before
   void execute();
   // void undo(); // no longer neeeded!
private:
   int oldHeight, newHeight;
};

The execute() functions need to call the partially implemented execute() function defined in the Command base class. Recall that this function instructs the model to create a momento:

void SetHeightCommand::execute()
{
   Command::execute(); // make a memento
   Brick* b = (Brick*) theModel;
   oldHeight = b->getHeight();
   b->setHeight(newHeight);
}