Flex Application Frameworks and Singletons
I've been looking at a number of Flex frameworks lately, and common patterns used in Flex application development. One thing that surprises me is how often I've been encountering singletons.
The Singleton pattern allows a class to enforce that there is only ever one instance of the class, and usually gives you an easy way to access it. Typically it looks like this:
[cc lang="actionscript"]
// a typical singleton
package org.stevex.myapp.model
{
...
public class DocumentLocator
{
private var _document:Document;
public function getActiveDocument():Document
{
if (_document == null)
{
_document = new Document();
}
return _document;
}
}
[/cc]
There's more to it than that if you want to enforce that there ever only be one instance of Document; see Grant Skinner's article here for some techniques.
Cairngorm's ModelLocator lets you find your model from anywhere. PureMVC's Facade.retrieveProxy() does the same thing.
You may call these singletons. You know what I call them? Global Variables. And in my world, global variables are a bad thing.
Once your application is bigger than a few source files, you need to start thinking long term. Maintenance and reuse. How is the application going to evolve? Often, in ways you didn't expect.
Here's a key design pattern that I recommend. I don't know if it's got a name, which may not make it as cool as calling something a Singleton, but it goes as follows: Always provide context.
By context, I mean that a function should be able to find all the information it needs to do its job from either its arguments or instance members. If it's a static function, this means you have to pass in all the data the function needs to work.
It's the difference between:
[cc lang="actionscript"]
public static function printDocument()
{
var doc:Document = DocumentLocator.getActiveDocument();
... print the document ...
}
[/cc]
and
[cc lang="actionscript"]
public static function printDocument(doc:Document)
{
... print the document ...
}
[/cc]
This is a fairly simplistic example, but you get the point. The first function gets the active document and prints it, and the second function requires the document be passed in.
The former is simpler, because you can call printDocument from anywhere. For example:
[cc lang="xml"]
[/cc]
There, you've got a button and when you click it, it prints the active document. What's wrong with that?
Here are a couple of scenarios where you'd get into trouble.
What happens when you go from editing a single document to allowing the user to have multiple documents open? Okay, so the method is called getActiveDocument(). You can track what document is "active", right?
What makes a document active? UI focus? The last one the user interacted with? This too will work, short term, but eventually lets say that the application needs to fetch some data from a server before printing. The user clicks a button, the request goes out to the server, and while waiting for that to return, the user switches to a new document. Now getActiveDocument will return the new document and print the wrong one.
Instead, you need to pass some context around. So now the view needs to get the document from somewhere to pass it to the printDocument function. Exactly how this would work depends on how your app is architected and what framework you're using, but it's always possible.
Why am I on about this? I've been a C++ developer for a long time, and come from a world of multi-document editors, where these issues are nothing new. Flex started out in a single document world - a web page - but now with AIR it's going to become much more important as multiple document editors start to become the norm. And it's much easier to prepare for up front than to have to revisit your code later.
Technorati Tags: flex