2.1.14 Recording Model
Motivation
A Recording Model maintains a log of the changes occurred to its state. This information can then be used by external client code, for example to perform a refresh only if the visualized information was changed, or to perform undo.
This technique carries the liability of forgetting to clear the log, leading to memory exhaustion.
Practical Example
The following example shows a Model class that records changes to its properties
class Customer(Model):
def __init__(self):
self._changes = {
"name": [],
"surname": [],
"address": []
}
self._name = None
self._surname = None
self._address = None
def set_name(self, name):
old_name = self._name
self._name = name
self._changes["name"].append((old_name, name))
self.notify_listeners()
# <similar code for set_surname/set_address
def changes(self, property_name):
return self._changes[property_name]
def clear_changes():
for changes in self._changes.values():
del changes[:]
The setters record the changes in the self._changes
dictionary. Performing the following operation
c = Customer()
c.set_name("Rob")
c.set_name("Robert")
will produce a self._changes["name"]
list containing two elements: the first transition (None, "Rob")
,
and the second transition ("Rob", "Robert")
.
Variation: record the sequence of changes
The solution given above does not record if, for example, the surname was changed before or after the name.
An alternative implementation can store this information by e.g. using a list instead of a dictionary
for self._changes
.
class Customer(Model):
def __init__(self):
self._changes = []
# <...>
def set_name(self, name):
# <...>
self._changes.append(("name", old_name, name))
# <...>
def changes(self):
return self._changes
Variation: interest only in the last change
The log length can be limited, potentially to a single change, by simply replacing the previous change information with the latest. This approach also removes the liability of forgetting to clear the log.
class Customer(Model):
de f __init__(self):
self._last_change = None
# <...>
def set_name(self, name):
# <...>
self._last_change = ("name", old_name, name)
# <...>
def last_change(self):
return self._last_change