Lazy pattern is about deferring all the work (processing, rendering, instantiating and/or loading objects) to the time when it is actually needed. This is of a more broader pattern about Asynchronous Processing which implements Two phases commit to process workload.
In the flex Spark component framework, there is this “Validation/Invalidation model” as Deepa Subramaniam calls it which is there to make our code work faster in Flash Player (code execution – rendering per frame in the FP rendering model) .
Scenario: In flex, “Invalidation is a useful mechanism for eliminating duplicate work by delaying processing of changes to a component until a later screen update”. If a user freaks out and drags a coverflow scrubber 100 times a second, we would like to defer all these crazy requests down to a reasonable volume that we think actually makes sense: For example, if we are running our swf 60 frames/sec, it’s totally reasonable to just process those updates 60 times/sec in maximum right before the rendering phase since all the extra updates would be not only wasted/unseen, but also an overhead for the Player. This is of a kinda humane example. There are probably a lot more times when you need to do this deferring to deal with the internal events from FP or the framework. There are other aforementioned scenarios when you have to coordinate all the different requests (you cannot process one until you have had some other ones being processed), as discussed in Corrollation Identifier Pattern and Competing Consumers Pattern.
Concept: The idea is to cache the requests and separate them from the processing. As in the real world, our immediate response to a request is to take notes, and do the actual work at our leisure later on (mostly as a batch for all work until that moment). Also watch out Starbucks’ decoupling cashier from baristas example next time you go there waiting in a queue. In order to do this in our component framework, additional layers are needed. This is how “dirty flags and storage variables” kicks in.
Solution: Dirty flag and storage variables
We do this by setting up control flags to indicate the state change of the objects of our interest. These flags serve as guards around heavy computations to make sure we’ve only re-calculating what we need to on any given pass. We also need storage variables to remember the requests. When the time to do the real work comes, we check against the guards and do (or bail out and do nothing;) the real processing by referencing to the variables which have stored the request information. The following code demonstrates how mx.core.UIComponent responds to a request to set current state of it:
public function setCurrentState(stateName:String,
playTransition:Boolean = true):void
// Only change if the requested state is different. Since the root
// state can be either null or “”, we need to add additional check
// to make sure we’re not going from null to “” or vice-versa.
if (stateName != currentState &&
!(isBaseState(stateName) && isBaseState(currentState)))
requestedCurrentState = stateName;
playStateTransition = playTransition;
_currentStateChanged = true;
// We need to wait until we’re fully initialized before commiting
// the current state. Otherwise children may not be created
// (if we’re inside a deferred instantiation container), or
// bindings may not be fired yet.
Why do we need the dirty flags? It’s not always the component that invalidates itself: you should always use flags to mark some potentially intensive processes in the validation phase so they don’t get executed needlessly.
- When a component changes size, it invalidates its parent’s size and display list.
- When UIComponent#includeInLayout changes, the parent’s size and display list are invalidated.
- UIComponent#styleChanged() invalidates the parent’s size and display list.
This pattern as implemented in Spark framework also reminds us of the MVC Pattern. The dirty flags and storage variables actually serve as the controller which handles the requests. The view doesn’t necessarily reflect this request for change in our model until it’s actually been processed. The dirty flags are there to remember whether the Model and View have been synced or not since the last time processing.
There are similar or similarly sounding patterns. One is tied to object initialization (“Lazy Load” with variations such as “Lazy initialization”); and another is about sperating the data being validated from the actual validation implementation (“Data Validation Pattern“), which is somehow different from but yet similar in some aspect to what we are talking about here from a pattern’s point of view (In lazy validation, we seperate what needs to be validated from the processes that actually do the real validation).