|
|
YOUR FEEDBACK
Did you read today's front page stories & breaking news?
SOA World Conference
Virtualization Conference $200 Savings Expire May 16, 2008... – Register Today!
SYS-CON.TV SYS-CON.TV WEBCASTS |
MXDJ TOP LINKS YOU MUST CLICK ON ! Developer Viewpoint
Un Momento, Por Favor
A brief glimpse into software design patterns and their usefulness
By: James O'Reilly
Oct. 21, 2006 07:15 PM
Digg This!
When developing applications, it's very common to find situations where you'd like to remember the state of an application, either in whole or in part, and later return your application to a previous state.
Your footsteps echo down the unmarked path. Gravel shuffles everywhere as you slow and strafe around the corner of a generic concrete bunker. You reach for the double- barreled shotgun but it's too late. A loud bang rips through the air but it's the soft thud as you hit the ground that confirms your worst fear, you're dead...again. A quick click of the mouse and poof...like magic you're all the way back to your last reached checkpoint. If you're like me, you're all too familiar with this scenario. When you reach the checkpoint for the first time, the application quickly stores essential information about your character's current state. Your state might consist of things like health percentage, the existence and condition of body armor, a list of carried items and your checkpoint location. This information is bundled into a "game state" object and stored quietly behind the scenes. Later on, when you fail miserably to reach the next checkpoint, the game state object is loaded and the application is restored to a previously defined state. In addition to the application state as a whole, you may find the need to record the state of smaller parts. We can also find examples of this in our favorite first-perso n shooter. For example, the state of a room you enter might be stored in a "room state" object when you leave the room. This object may store a list of items and their locations, existence of any damage, etc. This way, the guard you fragged will still be lying on the floor and the health pack you picked up will still be missing when you re-enter the room later. A "caretaker" object would be responsible for holding each of a level's room state objects in a randomly accessible list so that the application can retrieve the state of any room it needs to. By utilizing a room state object, when you leave a room the game is able to unload the overhead the room might consume with its textures and objects yet maintain the ability to easily recreate the room by loading it in its default state then modifying it with information found in a room state object. While these examples are game-specific, the same concept can be seen in almost any application. In fact, the undo feature is the quintessential example of restoring an application to a previous state. Multiple undos are implemented by storing command objects in a stack. The last command added to the stack is the first to be retrieved by CTRL+Z, creating a last-in, first-out scenario. From a mile-high view, the undo feature, room states, and checkpoint spawning are all basically the same thing. Therefore, it would be reasonable for us to assume that each of these scenarios can be implemented in a similar way if we were to describe their solutions from a similar distance.
Software Design Patterns Critics of design patterns argue that the abstract solution a design pattern provides often increases the amount of code needed to implement the solution. They also state that, by adding code not specific to the project, you go against the principles of "best practice" programming. Many advocates of design patterns, like me, recognize these cons but believe the pros outweigh them by far and do, in fact, promote "best practice" solutions in a way of their own. Yes, with design patterns you're implementing abstract solutions, but so what? After all, if it's considered "best practice" to design abstract classes, why can't solutions be abstract? To me, patterns end up providing a more scalable solution than I might have implemented had I chosen to write something specific to the project. Another major advantage is the ability to have a common language with other developers, especially ones I've never met. Without design patterns, developers working in teams need to do more planning and collaboration to implement the same solution, since each developer's prior experience may have led them to different solutions to the same problem. "Hey Mike, I think we need to take a snapshot of the game at each checkpoint so that we can restore the game to a point in time when the player dies." "Yeah, you're right, John. I remember on the Acme project we wrote some classes that stored small pieces of information we later used to restore the application." "I dunno, I didn't work on the Acme project so I'm not at all familiar with how they handled it. But what you describe sounds more like what we did on the Foo video player." "No, not really. With the Foo player we had that hack Joe work on the project and we ended up changing it a bit afterwards. I was thinking more like..." Anyway, you get the idea. Wouldn't something like the following be easier? "Hey Mike, I think we should implement the Memento design pattern for the room states." "Yeah, no doubt. I'll go ahead and write the memento class. Do you want to write the caretaker class?" By implementing a design pattern, the developers can reuse the amount of time spent on this feature.
The Memento Pattern The Memento pattern is typically made up of three objects: the originator, the memento, and the caretaker.
Let's examine a simple version the Memento design pattern by creating a Flash SWF player you might typically see on the homepage of a site. The main SWF is a parent SWF that loads children SWFs, each of which play as animations and have some level of interactivity. In this example, the main SWF would be the caretaker, the currently loaded child SWF would be the originator and the memento would be an object created by the child and stored in the parent. The reason we need to store the memento in the caretaker and not the originator is that we'll unload the originator when we load the next SWF in the playlist. By using a caretaker, the memento can persist after the originator is gone. For a simple illustration of the concept, I show the implementation below using more of a procedural method of programming. An object-oriented approach would be better to enforce encapsulation and prevent non-originator access to the memento content. On my Web site at www.jamesor.com/downloads/wddj/mementos.zip you can find the full source code to both procedural and object-oriented implementations. In our parent movie, we create a list to hold our memento objects:
// list to hold memento objects On frame one in our each of our child movies, we include getter and setter like functions for creating and restoring mementos:
function getCurrState ():Object { Since we defined our memento object inside the child SWF, we can have unique memento definitions for each child we load. The caretaker doesn't care what's inside the memento objects; it just stores them in an array and returns them as objects when needed.
Occasional Connectivity One way to improve a user's experience and meet their ever-increasing expectations of RIAs might be to implement the Memento pattern on a complex form. This way, if a connection is lost before the user gets to submit a complex form, you could create a memento object that contains all of the form field data on the screen. This memento object can be stored on the user's hard drive and later retrieved so it can be submitted the next time an Internet connection is available. Using the SharedObject, we can easily store and retrieve a memento object.
// Get the flash cookie named LATEST FLEX STORIES & POSTS
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||