Check out our new training course on AngularJS for Flex Developers

Learning Cairngorm (Part 6) Dealing with the Singleton

There was a presentation a while ago talking about the different frameworks in Flex. The presenters speak ill of Cairngorm's use of Singletons (It's about 20 minutes in, but I strongly recommend watching the whole thing if you haven't seen it yet). I thought it would be a worthy discussion to discuss the complaints with Singletons, how they relate to Cairngorm, and how I deal with this when building Cairngorm applications.

What is a Singleton

Singleton is a design pattern. It is a class that is only instantiated once. Only a single instance of the singleton object will exist. The most common use of singleton that I've seen is as a location for global data. Sometimes Singletons are used in frameworks as a single point of entry into the framework APIs.

In the ColdFusion world, the application or session scope might be considered a singleton. In Cairngorm, the ModelLocator is a singleton. Using the Cairngorm paradigm, most components refer to the ModelLocator for global application data, figuring out what the state of the application is. I really like the way that the Cairngorm ModelLocator can be used in conjunction with ViewStacks and binding to display screens to the user.

Problems with Singletons

So, a Singleton is a class that is a global data store. Why is this bad? In no particular order:

  • In most Cairngorm applications I've seen, all components are referencing the ModelLocator. That means these components are not portable to other projects because they are specifically tied to the application. You are creating dependencies and there is no loose coupling.
  • If the components you're building are not stand alone, then it becomes complicated, if not impossible, to perform unit tests on the component. This can lead to more time in development.
  • Flex, or more appropriately, ActionScript 3, does not have private constructors. As such workarounds are used to prevent multiple instances of the class from being created. In the grand scheme of thing, this is a minor issue.
  • Unless you write code to "Destroy" / get rid of the stuff you are storing in the ModelLocator, it will hang out there for as long as your application is in use. In some cases this is fine. In others it can be wasteful. Loading and storing too much data could lead to memory issues.

How can I code avoid singleton problems in Cairngorm?

So, how can you write Cairngorm applications in such a way that they avoid the problems associated with singletons? Well, in reality, you can't. but, you can try to organize your application to minimize the use of the ModelLocator; which is what I Try to do:

  • Top Level Application: The Top level application is my main.mxml file; the one with the Application (or WindowedApplication in AIR) root. I think it's a pretty safe bet that this will be tightly coupled with the application, and reuse on this will be rare. I'm completely fine with that. As such, it's perfectly fine for my main.mxml to reference the ModelLocator. The Main.mxml often contains a ViewStack of the Application screens, but not much else.
  • Second Tier Components: The second tier components are the main screen containers. I'll generally have one of these components for each 'viewstack' index in the main application. I figure it is okay if these are tied tightly to the application, and therefore they can access the ModelLocator.
  • Everything Else: The second tier components will be made up of plenty of other components (Most likely using composition). Any level below the second tier, I try to make as loosely coupled as possible. Instead to referencing global data in the ModelLocator, I'll exchange data using parameters and events. In an ideal world, I'd only have 3 layers of components, but realistically these can trickle down much further just 3 layers.

I've found that implementing this use of the ModelLocator has given me a good balance of using "Global Variables" with loosely coupled components.

I wasn't ever planning on adding another entry into my Cairngorm series, but this has been stewing in my idea pool for a while, and tonight I felt inspired. While you're reading this, don't forget about the upcoming DotComIt focus group. Flex Developer's of all levels are welcome to attend.

Related Blog Entries

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Theo's Gravatar My suggestion to avoiding singleton creep is to reverse the pattern and use dependency injection instead. What you could do in your architecture example is to retrieve the ModelLocator in your top level Main.mxml and then inject it into the second tier (i.e. the second tier components have a property called modelLocator which you set to a reference of the ModelLocator singleton). Preferably you hide the ModelLocator instance behind an interface, that way you can inject a mock when testing or you can create a mediator if you want a layer of negotiation beteween you and the ModelLocator, and perhaps you could even switch to something other than Cairngorm and still be able to reuse your components, since they would be talking to your interface, not to the Cairngorm ModelLocator directly (there would, of course, be other problems with switching the whole framework).

The major problem with singletons is your first bullet, that nothing works without it, and the reason for that is that Cairngorm seems to me to encourage people to use it as a global variable. If you don't then you are probably better off.

I should add that I have never used Cairngorm, I evaluated it much like Luke and Ali did and the documentation completely put me off.
# Posted By Theo | 3/28/08 3:33 AM
Jeffry Houser's Gravatar Theo,

Let me regurgitate this and see if I understand.

My "second tier" components would some variable that implements an interface like this:

[Bindable] model : 2ndTierView1Interface;

That interface would implement various methods or properties needed in that "screen".

The Model Locator would them implement that interface, something like this:

public class MyModelLocator implements ModelLocator , 2ndTierView1Interface

And my main.mxml would just pass in the ModelLocator as a parameter to the component, something like this:

[Bindable]public var model : MyModelLocator = MyModelLocator.getInstance();
<mx:View1 model model ="{MyModelLocator}" />

Do I have that right? It seems like a very elegant solutions; and makes the "Second tier" components more portable than they would be otherwise.
# Posted By Jeffry Houser | 3/28/08 8:24 AM
Theo's Gravatar Yes, almost right. You don't have to go so far as to have a specific interface for each 2nd-tier view, rather you could have one single interface for you applications model, for example "MyAppModel". That interface defines all properties and actions of your model and business logic, and it does it in a way specific to your application, but not specific to the framework you use.

If you decide that you want to change something you can change the concrete implementation that you pass to your views, either creating a mediator that handles some of the things and delegate other things to the old model, or a completely new model implementation.

You could have a number of different interfaces that you pass to different views, it could actually be a more robust and reusable system, but in most cases I think it would be overkill, 2nd-tier views are usually too application specific anyway.

Glad you like the idea.
# Posted By Theo | 3/28/08 9:10 AM
Bob's Gravatar Thanks for the series of articles.

I was thinking about Singleton's and tiers of components just today after looking at Jesse Warden's 10 Tips For Working With Cairngorm @ http://jessewarden.com/2007/08/10-tips-for-working...

Specifically his point #10
"10.Try not to have View’s use CairngormEventDispatcher (or Events that extend CairngormEvent use event.disaptch()).
Instead, have those deeply nested views dispatch events. Either bubble them up so a master controller View can then fire off Cairngorm events, or bucket-brigade them up...." and he then continues to explain further.

Not really sure but thinking maybe his "master controller View" is related to your "Second Tier Components" ?
ie the "Everything Else" tier simply fire regular events and pass params to their "Second Tier" wrappers that fire the appropriate CairngormEvent, similarly maybe each "Second Tier" contains real links to the ModelLocator Singleton that their "Everything Else" tier simply reference.

Think there is some connection there but not got my head around it properly though as I am just starting with Cairngorm :)
# Posted By Bob | 3/28/08 10:46 AM
Jeffry Houser's Gravatar Bob,

Thanks for reading.

I think that Jesse's description of a "master controller view" matches my "second tier component". The reason he wouldn't want to use the Cairngorm Event Dispatcher in views is because that makes it less portable to move to a non-Cairngorm based application.

At least that is what I would guess, anyway.
# Posted By Jeffry Houser | 3/28/08 11:43 AM
newbie's Gravatar "Instead to referencing global data in the ModelLocator,
I'll exchange data using parameters and events."

What does the second line mean in practice ?
# Posted By newbie | 4/30/08 1:33 PM
Jeffry Houser's Gravatar Hi Newbie,

Parameters means defining public variables in a component, and accessing them from a component which contains the other component. This is how you get information into a component.

Events are how a component tells other components (or the application) that something occurred inside it.

There should be plenty of documentation on the Flex Component model in the Flex docs.
# Posted By Jeffry Houser | 4/30/08 2:18 PM
Dhivya's Gravatar i am a new comer to cairngorm ,
could you pls tell me why we need to go for
cairngorm and the difference between cairngorm
version 2 and 3
# Posted By Dhivya | 7/8/11 1:59 PM
Jeffry Houser's Gravatar dhivya,

The best I can offer you is to direct you to some info about Cairngorm 3:

http://opensource.adobe.com/wiki/display/cairngorm...

http://blogs.adobe.com/auhlmann/2010/10/cairngorm-...

I haven't done any in depth comparisons personally.
# Posted By Jeffry Houser | 7/19/11 7:04 AM
All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version 5.9.2.002.