nwebb

Flex, Flash, AIR

Drag, Drop and Update Example

I got an MSN from a good friend earlier this afternoon, asking if it was possible to drag an item from one DataGrid in to another DataGrid, and have the second DataGrid update/inherit the properties of that item, rather than the default behaviour, in which the dragged item gets added as another row.

I've not played around with the DragManager up until now so I gave it a whirl and came up with this example (I have a slight nagging feeling that I may have overlooked an easier way of achieving this(?)), but hey it was a fun way to spend an hour :]

The code is pretty straight forward - it took me a while to find out how to obtain the drop-position of the item - I was initially expecting it to be a property of the event object, and also to get the xml of the drag object using dataForFormat, but it is all in the docs.

I'm going to post the code as-is as I'm in a rush to get away for the weekend, but I'll almost certainly come back to it, comment it, tidy it up, add new features (e.g. allow the items on the right to be re-ordered, remove items from the left-DataGrid by using MOVE rather than COPY etc ). This should give you something to play with if you're interested.

Just copy and paste all the code in to a (default application) .mxml file and run the app. Here's what it should look like:

Actionscript:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="init()">
  3.    
  4.     <mx:Script>
  5.         <![CDATA[
  6.             import mx.controls.List;
  7.             import mx.collections.IList;
  8.             import mx.events.FlexEvent;
  9.             import mx.automation.delegates.DragManagerAutomationImpl;
  10.             import mx.managers.DragManager;
  11.             import mx.events.DragEvent;
  12.             import mx.core.DragSource;
  13.            
  14.             [Bindable] private var xmlList1:XMLList;
  15.             [Bindable] private var xmlList2:XMLList;
  16.             private var xml1:XML =
  17.                             <top>
  18.                                 <person name="AAA" age="10"/>
  19.                                 <person name="BBB" age="20"/>
  20.                                 <person name="CCC" age="30"/>
  21.                              </top>;
  22.                             
  23.             private var xml2:XML =
  24.                             <top>
  25.                                 <slot num="1" start="09.00"/>
  26.                                 <slot num="2" start="10.00"/>
  27.                                 <slot num="3" start="11.00"/>
  28.                              </top>;                
  29.            
  30.             private function init():void
  31.             {
  32.                 xmlList1 = xml1.person;
  33.                 xmlList2 = xml2.slot;
  34.                 dg2.addEventListener(DragEvent.DRAG_DROP, onDragDrop);
  35.             }
  36.            
  37.             private function onDragDrop(event:DragEvent):void
  38.             {
  39.                 if (event.dragSource.hasFormat("items"))
  40.                 {
  41.                     event.preventDefault();
  42.                     event.currentTarget.hideDropFeedback(event);
  43.                     var dropTarget:DataGrid = event.currentTarget as DataGrid;
  44.                     var dropIndex:int = dropTarget.calculateDropIndex(event);
  45.                     var dropTargetItem:XML = dropTarget.dataProvider[dropIndex];
  46.                     var items:Array = event.dragSource.dataForFormat("items") as Array;
  47.                     var newXml:XML = items[0];
  48.                     var mergedNode:XML = mergeXml(dropTargetItem, newXml);
  49.                 } 
  50.             }
  51.            
  52.             private function mergeXml(dropTargetItem:XML, newXml:XML):XML
  53.             {
  54.                 var attName:String;
  55.                 var attValue:String;
  56.                 for each(var att:XML in newXml.attributes())
  57.                 {
  58.                     //TODO: do a check here to ensure attribute doesn't already exist etc
  59.                     attName = att.name();
  60.                     attValue = att.toString();
  61.                     dropTargetItem["@" + attName] = attValue;
  62.                 }
  63.                 return dropTargetItem;  
  64.             }
  65.                                         
  66.         ]]>
  67.     </mx:Script>
  68.    
  69.     <mx:HBox>
  70.         <mx:DataGrid id="dg1" dataProvider="{xmlList1}" dragEnabled="true">
  71.             <mx:columns>
  72.                 <mx:DataGridColumn headerText="Name" dataField="@name" />
  73.                 <mx:DataGridColumn headerText="Age" dataField="@age" />
  74.             </mx:columns>
  75.         </mx:DataGrid>
  76.        
  77.         <mx:DataGrid id="dg2" dataProvider="{xmlList2}" dropEnabled="true">
  78.             <mx:columns>
  79.                 <mx:DataGridColumn headerText="#" dataField="@num" />
  80.                 <mx:DataGridColumn headerText="Start" dataField="@start" />
  81.                 <mx:DataGridColumn headerText="Name" dataField="@name" />
  82.                 <mx:DataGridColumn headerText="Age" dataField="@age" />
  83.             </mx:columns>
  84.         </mx:DataGrid>
  85.     </mx:HBox>
  86. </mx:Application>

No comments

Publishing Your SWF to a Remote (Development) Environment

The previous project I worked on received a config file at start-up which contained absolute URLs, so I could happily run & debug my application locally and everything worked (i.e. I didn't need to specify an 'output folder' or 'output folder url' in my project settings).

Recently I started a small project and wanted to publish the .swf to a development location on the network. I'm primarily a front end developer, so when it comes to server stuff and windows protocols I'm admittedly on slightly shaky ground. I ran in to a minor problem getting my .swf to publish to the correct location and I thought I'd share it in case it is of use to others. Those in the know may laugh at my faux-pas, but hey if you don't know you don't know!

I develop on a Windows machine, so when I want to access another machine on the network I'm used to using double back-slash syntax ( what I now know to be UNC ). For example:
Start -> run -> \\devmachine\c$\wwwroot\projectname\foldername

Therefore, when I went to set the 'output folder' (in the settings for Flex Build Path) I attempted to set it as \\devmachine\c$\wwwroot\projectname\foldername

Flex properties, build path

As you can see from the above image, there is a 'browse' button which you can use to set the path, but you can't browse to a UNC location (as far as I'm aware), so I thought I could just paste in the UNC. It didn't work and my file never got published to the correct location.

As it turns out, for Windows to be able to address a network location, that location must be mapped to a drive letter, so the solution is simply to map the drive and browse to the location using the browse button.

e.g. \\devmachine\c$ gets mapped to Z, and so the output folder location becomes Z:\wwwroot\projectname\foldername

...while the output folder url will look something like http://projectname/foldername/

Easy when you know how.

1 comment

Creating Classes Dynamically By Name

On occasion you may want to create classes dynamically by name. To do this in Flex 3 you can use getDefinitionByName (it's previous incarnation was getClassByName). Here's a quick example:

Actionscript:
  1. //cc() is called upon creationComplete
  2. private function cc():void
  3. {
  4.         var obj:Object = createInstance("flash.display.Sprite");
  5. }
  6.  
  7. public function createInstance(className:String):Object
  8. {
  9.         var myClass:Class = getDefinitionByName(className) as Class;
  10.         var instance:Object = new myClass();
  11.         return instance;
  12. }

The docs for getDefinitionByName say:

"Returns a reference to the class object of the class specified by the name parameter."

...so you may be wondering why in the above code we needed to specify the return value as a Class? This is because getDefinitionByName can also return a Function (e.g. 'flash.utils.getTimer' - a package level function that isn't in any class). As the return type can be either a Function or a Class the Flex team specified the return type to be Object and you are expected to perform a cast as necessary.

The above code closely mimics the example given in the docs, but in one way it is a bad example because everything will work fine for "flash.display.Sprite", but try to do the same thing with a custom class and you will probably end up with the following error:

ReferenceError: Error #1065: Variable [name of your class] is not defined.

The reason for the error is that you must have a reference to your class in your code - e.g. you need to create a variable and specify it's type like so:

Actionscript:
  1. private var forCompiler:SomeClass;

Without doing this your class will not be compiled in to the .swf at compile time - and there is reason behind this madness. The compiler only includes classes which are actually used (and not just imported). It does so in order to optimise the size of the .swf. So the need to declare a variable should not really be considered an oversight or bug, although it does feel hackish to declare a variable that you don't directly use.

Here is the code your would need to create a custom class called Person from a string (where Person resides in the top level package along with your default application).

Actionscript:
  1. //cc() is called upon creationComplete
  2. private var forCompiler:Person; //REQUIRED! (but otherwise not used)
  3.  
  4. private function cc():void
  5. {
  6.         var obj:Object = createInstance("Person");
  7. }
  8.  
  9. public function createInstance(className:String):Object
  10. {
  11.         var myClass:Class = getDefinitionByName(className) as Class;
  12.         var instance:Object = new myClass();
  13.         return instance;
  14. }

You can declare properties for all possible classes that you intend to create but if you are not happy with doing that inside your main app Alex Harui has another suggestion (something I've not personally tried yet):

"The code for the class has to be in a SWF. It can be in the main SWF or
loaded via a module later. There is a compiler option (-includes) that
allows you to stuff other classes into a SWF without explicitly naming
them in your source code."

Passing in Parameters

Another thing you may find yourself wanting to do is to pass parameters to the constructor of your class (indeed, this is what got me on to the subject today). As far as I'm aware this isn't possible to do this in AS3 (and isn't part of the ECMA spec so it is unlikely to change - please leave a comment or email if you know otherwise ), so you may want to set up another method which can accept and set multiple parameters . If you pass in an array you may stumble across another problem - the original array you passed in becomes the first item of a new array ... okay, that probably sounds confusing so see here for a similar example and solution. In short, the solution is to use Function.apply, and you can see how I used it below:

Actionscript:
  1. private var forCompiler:Person;
  2.  
  3. private function cc():void
  4. {
  5.         var obj:Object = createInstance("Person", ["bob", 30]);
  6. }
  7.  
  8. public function createInstance(className:String, args:Array):Object
  9. {
  10.         var myClass:Class = getDefinitionByName(className) as Class;
  11.         var instance:Object = new myClass();
  12.         instance.initArgs.apply(null, args);
  13.         return instance;
  14. }
  15.  
  16. /*********************************************************************
  17. //In person.initArgs()....
  18. //Note: the constructor also accepts name &amp; age, assigning them default values
  19. //if not specified.
  20. public function initArgs(name:String, age:uint):void
  21. {
  22.         this.name = name;
  23.         this.age = age;
  24. }
  25. *********************************************************************/

Now, I'm not sure if this is the best approach, but it works, and with a deadline approaching that's good enough for now :]

No comments

Snippets in FlexBuilder

Snippets can be a real boon to development.
If you're using Flex you will want something that can handle markup and well as code.

About this time last year I read an excellent blog post from fellow developer Jun, regarding snippets in Eclipse (read:FlexBuilder), but I had some issues due to incompatible versions of programs I was running (plus I found this nasty little bug).

I have just installed a fresh copy of Eclipse ( 3.3.2 ) & the FlexBuilder plugin ( 3.0.194161 ) ... as well as getting the latest JDK ( jdk-6u6-windows-i586-p.exe ) in order to resolve this issue .... and I'm happy to say I was able to install and start using snippets straight away.

To do likewise you will need the Web Standards Tools for Eclipse (you can get this for the FlexBuilder standalone too, as FB still runs atop Eclipse,  but you may run in to those version issues I alluded to earlier, and I generally advise using the plugin version of Eclipse rather than the standalone, as it gives you greater freedom).

Jun did a great job of posting about the Snippets tool, so I just wanted to add to that by clarifying how to install the WST from within Eclipse. Click on the thmbnails below for full size screen captures:

1. From the Eclipse Help menu, find and install software updates...

2. Check for new features to install...

3. Select the Europa Discovery Site (WST is listed under the Web and JEE Development subfolder)

4. Select 'Web Standard Tools'. You may need to uncheck 'Show the latest version of a feature only'. If an error symbol appears next to your selection (as shown in the screen grab) press the 'Select Required' button and Eclipse will automatically select any other updates upon which WST depends.

5. Follow the rest of the installation procedure, and finally restart Eclipse when asked. Once it has restarted, go to: Window -> Show View -> Other... -> General [folder] -> Snippets...

6. Add the Snippets panel to your workspace. To set up snippets, right-click on the panel and choose 'Customize...' . As you can see from the screen grab I have set up two headers, one of which is expanded to show my first snippet. Adding a snippet is an easy as double-clicking it.

For more screenshots of the Snippet tool itself, go here

1 comment

*Upgrading WordPress*

Please bear with me while I find replacement plugins and rejigg my upgraded installation of WordPress.

[ edit - just installed a new syntax hiliter - now all I have to do is go through every old post and .... ;] ]

No comments

Running Your Test Cases Automatically

A while ago I wrote a tutorial on Unit Testing and Test Driven Development for Adobe, and earlier this week somebody (and I've completely forgotten who, sorry!) asked me to clarify a point in the article, where I alluded to a way of automatically running all test methods which begin with the word "test". I thought I'd posted about it ages ago, but looks like I was mistaken [EDIT: nope - here it is!].

There are two changes needed, and both are located in the same file (AccountTest.as)

1. In the constructor, AccountTest(methodName:String) should be given a default value of null, and therefore becomes AccountTest(methodName:String = null)

2. Rather than adding tests using addTest, we add a testSuite using addtestSuite. We no longer need to pass in the string name of the method.

Here is the relevant part of the class, with the old code commented out:

Actionscript:
  1. public class AccountTest extends TestCase
  2. {
  3. //Give the methodName param a default value of null
  4. public function AccountTest(methodName:String = null)
  5. {
  6. super(methodName);
  7. }
  8.  
  9. public static function suite():TestSuite
  10. {
  11. var accountTS:TestSuite = new TestSuite();
  12. accountTS.addTestSuite(AccountTest); //*- this is new
  13.  
  14. //This is too much like hard work:
  15. //accountTS.addTest(new AccountTest("testNew"));
  16. //accountTS.addTest(new AccountTest("testCreditWithNullValue"));
  17. //accountTS.addTest(new AccountTest("testCreditWithRealValue"));
  18. //accountTS.addTest(new AccountTest("testCreditWithRealValueTothreeDecimalPlaces"));
  19.  
  20. return accountTS;
  21. }
  22.  
  23. //OTHER METHODS HERE.....
  24. }

Now when you run the project, all your methods within this class which begin with the word 'test' will run automatically. Much better eh :]

No comments

2 Random Flex Tips

When I end up helping someone with Flex, it nearly always gives me an idea for a new tip post :]

Creating A Nested Folder Structure In FlexBuilder

I've seen my fair share of people create their folder structures the long way round, and not just those who are new to Flex, so here's a tip... right-click on your project -> new -> folder -> [type the folder(s) you want to create]

folderpath_flexbuilder

No, The Combo Prompt Isn't Lost
I don't know if this is a commonly held [mis]belief, but twice I have heard people say that if you have a combo with promp-text specified, and then select an item from the combo, the prompt will be lost ... forever! No it's not. To display it again simply reset the selectedIndex to -1 (as it says in the docs)

//initial combo setup
myCombo.prompt = "Select an item...";
myCombo.dataProvider = myDataProviderObject ;

... and then later on ...

//reset the combo to display the prompt
myCombo.selectedIndex = -1;
trace("yay");

2 comments

More Component LifeCycle Stuff (null error avoidance)

In the last post I wrote a little about the component life cycle and why it is useful to know about it even if you are not creating advanced components. Here is a similar situation you may find yourself in when extending components, which would result in an error being thrown ...

The HeaderBar Component

Let's say you have created your own simple "HeaderBar.mxml" component - all this does is extend Canvas and add a Label to display some text.

The label has an instance name of headerTextDisplay

[as my current WordPress plugin struggles with mxml, I'll just show the ActionScript code]

The script in your HeaderBar.mxml file would look something like this:

Actionscript:
  1. //Here we try to retrieve/assign the text directly to the Label instance
  2. public function get text():String
  3. {
  4.         return headerTextDisplay.text;
  5. }
  6.  
  7. public function set text(value:String):void
  8. {
  9.         headerTextDisplay.text = value;
  10. }

In your main Application file you instantiate a copy of your HeaderBar class through ActionScript ...

Here is what the script in your main.mxml file may look like:

Actionscript:
  1. private function onCreationComplete():void
  2. {
  3.         var header:HeaderBar = new HeaderBar();
  4.         header.text = "Hello World!";
  5.         addChild(header);
  6. }

Now that seems pretty reasonable to me, however, the call to set the text would result in the following error being thrown: Error #1009: Cannot access a property or method of a null object reference

The reason for this error is simple. At the time you try to assign the text, the Label (which is a child of your HeaderBar component) has not been created. If you read back through my previous post you will understand why - at this point we've not added our component to the display list, and so the component instantiation has only got so far. If we instead decide to add the child first and then assign the text, everything should work! However, when we create components they should not be as brittle as that. We want to be able to declare properties before we add the component to the display list. This is how all the inbuilt components work, and ours should follow suit.

Failure Is Not An Option

So how do we avoid this error and still allow the user of our component to set properties before adding it to a display list?

First of all we do not assign our property values directly to our component's children. Instead we store them in private variables until we are ready (there are other reasons for doing this, but they are beyond the scope of this basic tutorial - if you want to read more, there is an excellent chapter in Programming Flex 2). We also use boolean flags to "mark the properties as being dirty" - this is optional and in fact not needed at all for such a simple component, but as your component grows in size it will prevent code from being run unnecessarily, and is good practise so I'll show it in the example.

A Better Component

The code in our main.mxml file stays the same. It is only our HeaderBar.mxml file that changes. I'll show the code and then explain it in more detail:

Actionscript:
  1. private var _text:String;
  2. private var _textDirty:Boolean = false;
  3.  
  4. //In our setter we assign the text to a private variable. We
  5. //then tell the framework that one or more
  6. //properties are invalid.
  7. public function get text():String
  8. {
  9.     return _text;
  10. }
  11.  
  12. public function set text(value:String):void
  13. {
  14.         _text = value;
  15.     _textDirty = true;
  16.     invalidateProperties(); //calls commitProperties
  17. }
  18.  
  19. override protected function commitProperties():void
  20. {
  21.     super.commitProperties();
  22.     if(_textDirty)
  23.     {
  24.         headerTextDisplay.text = text;
  25.         _textDirty = false;
  26.     }
  27. }

So the fist thing we do is declare a private variable to hold our text value, and another variable which is a boolean flag. When the setter is called, the value gets assigned to the private _text variable, and not directly to the Label component. We also set the value of _textDirty to be true and call invalidateProperties().

Ignoring the _textDirty property for just a second, what the invalidateProperties() call does is to alert Flex to the fact that at least one of the properties has changed ... and therefore the values being used currently are invalid. This will cause Flex to re-assess the property values when it is next convenient, and it does that by calling a method called commitProperties() - you should never call commitProperties directly (again, this is beyond the scope of this post, but check out the recommended book or the Flex documentation for more info).

The _textDirty flag is for our own use - we want to mark which property or properties have changed since the properties were last assessed by Flex, and therefore we know which ones need updating. When commitProperties() is called by the Flex framework, we could update all properties, but by using a flag we can ensure we only update the ones which have changed - which is less processor intensive when your component has multiple properties and not all need to be updated.

So, without getting too heavily in to the component lifecycle, what we are doing is first saying "hey, our text property is the one that has changed", and then telling Flex to reassess all properties.

Committed

In the component lifecycle, the validation of properties does not occur until after the component's children have been created, and this is why you can be assured that when commitProperties() is called by the framework, all the child components, such as our Label, will have been fully instantiated. This is why we do the assigning of the text value to the Label component within the commitProperties method.

HeaderBar is a subclass of Canvas, so we need to override the existing commitProperties() method which belongs to the superclass. We do this using the override keyword and call super.commitProperties() to ensure that the superclass's method gets run first and does all the validation it needs to do for the properties of Canvas. Then we can add in our additional 'stuff'.

We only want to update properties which have changed, and this is where our boolean flag comes in to play - if it is 'true' then that property needs updating. In our case it is true for the text property, so we assign our updated text value to the ".text" property of the headerTextDisplay Label instance. We know that by this point in the lifecycle, the Label instance will exist, so we will not get that null object error. Finally we reset our flag to be false.

Finally

Here I've used a simplified example to try and give you an insight in to how you can make your components more sturdy, while explaining a little more about the component life-cycle. To some it may seem like too much effort, especially when you can just ensure you add your components to the display list before assigning values, but you will almost certainly come across situations down the line where this will not suit your needs, and so understanding more about how the Flex team build their components will help you produce more reusable items.

7 comments

Flex components & why that property doesn’t get set

Earlier today I fixed a minor code issue. It took seconds to identify, but I remember being a little stumped by a similar problem in my early Flex days. The difference now is that I'm familiar with the component life-cycle.

You may think it is only worth reading up on the Flex component life-cycle if you intend to create advanced components, but that's not true, even when you are doing nothing other than extending basic mxml components a little knowledge goes a long way.

To demonstrate the problem take a look at the init method for this simple mxml component called TimeInputBar (which extends Canvas).

Actionscript:
  1. //<code>Init</code> is called when the component's <code>initialize</code> event is fired:
  2. public var time:Number;
  3.  
  4. public function init():void
  5. {
  6.     time = 0;
  7. }

That's simple enough. Now take a look at the ActionScript which is creating an instance of the TimeInputBar:

Actionscript:
  1. var t:TimeInputBar = new TimeInputBar();
  2. t.time = 12;
  3. addChild(t);

Again, simple code, but did you spot the problem? With a little bit of knowledge it's easy to see that time will always be reset to 0 and will never be 12. Why?

When you create a component using the new operator, only part of the life-cycle completes. The component gets as far as the configuration stage, which means you can set properties on the component (to be processed by the component later) but the life-cycle will not go any further than that. It is in effect, paused.

However, all the really cool stuff in the life-cycle, like creating the component's child elements, measuring the component, drawing the component and dispatching events happens during the next stage.

It is only when you add the component to the display list using addChild or addChildAt that the life-cycle continues (in other words ... it continues when the component has a parent).

As mentioned, the next phase is the one in which the cool stuff happens: In more detail, this means that the preinitialize event is dispatched, the component's children are created, the initialize event is dispatched and the component's validation methods are called (those are beyond the scope of this article) and if that's not enough for you, when all that is done then everybody's favourite event, creationComplete is dispatched.

So, with that knowledge in hand let's revisit the order of execution for the original example:

  • Create component using 'new' operator
  • Set time variable to 12
  • Add component to display list
  • initialize event is fired
  • init() method is called
  • time variable is set to 0
  • Many beginners make the assumption that the preinitialize and initialize events are dispatched early on - don't beat yourself up, that's a reasonable assumption to make. However those events may actually be dispatched after you've set initial values for some of your component's properties.

    So, what's the solution? We could simply swap the order of our code:

    Actionscript:
    1. //no worky!
    2. t.time = 12;
    3. addChild(t);
    4.  
    5. //worky
    6. addChild(t);
    7. t.time = 12;

    ...but I'm hoping you can see the issue; components should be just a little more flexible than that!

    A perfectly acceptable solution here would be to perform a simple check inside our init method:

    Actionscript:
    1. public var time:Number;
    2.  
    3. private function init():void
    4. {
    5.     if(isNaN(time)) time = 0;
    6. }

    [Edit - it's also perfectly acceptable to set 'time' to 0 when you first declare it - this post is not really concerned with which solution you choose, but rather it uses simplified code to explain why such a problem may arise in the first place.]

    Once that is done, it will not matter if you set time before or after you add your component to the display list. If the value is set externally before init is called, the value will not be overridden.

    You can read a little more about the Flex component life-cycle in one of my earlier posts here.

    9 comments

    Using Cairngorm & Thoughts On Handling Those Pesky Singletons

    One assumption people tend to make about me is that because I post/speak about Cairngorm, I advocate it as being the best of the frameworks, and that's simply not true. However there are good reasons why I (currently) concentrate on Cairngorm:

    - it has a low barrier to entry
    - it comes from the Adobe camp
    - I have more experience with Cairngorm than with other architectural frameworks

    Before I talk about the Singletons I want to briefly expand upon two of those points. First of all it is comparatively easy for Flex developers to pick up and run with Cairngorm, even if they have no prior experience of design patterns. Bill Lane (GeekGlue) compares Cairngorm to the popular PureMVC framework in order to make a similar point here. We already have a situation where many Flex developers don't even know what an architectural framework is, so it makes some sense to introduce the easiest option, and from there they can make their own decisions.

    Cairngorm is also worthy of consideration because it is an Adobe product. Before you jump down my throat, no, that doesn't mean it's somehow instantly better than the alternatives, but like it or not many companies will choose to go with Cairngorm for this exact reason. Doug McCune brought this up at a recent SILVAFUG meeting, pointing out that if you’re a contractor working on other people’s projects and going from client to client, the only framework you must know is Cairngorm. This may change over time, but right now it's a pretty compelling argument to familiarise yourself with Cairngorm.

    The Problem With Singletons

    The main reason people tell me they dislike Cairngorm is due to its over-reliance on the Singleton design pattern, and I understand.

    Singletons increase coupling between classes and make them difficult to unit test. Any class which retrieves a singleton instance becomes unnecessarily coupled to the fact that the class is a singleton - it treats it in a different manor from other classes (i.e. it uses an uncommon instantiation technique). Singletons can't be substituted without changing the source of the class which uses it, nor can they be swapped-out for an interface, because singleton instances are retrieved/instantiated with a call to a static method ( getInstance() by convention ) and you can't have a static method on an interface. This limits polymorphism, going against the OO maxim "Program to an interface, not an implementation". Furthermore there is the issue of misplaced responsibility, as classes should not be responsible for limiting their own instantiation; that should be the responsibility of a factory or builder object.

    So, on one hand Cairngorm makes for a good choice, and on the other, Singletons throw a real spanner in the works. Is it possible to have the best of both worlds? Well, no, but maybe we can improve things slightly...

    Handling Singletons Outside of Cairngorm

    Coupling can be reduced across multiple classes if we address the instantiation aspect of singletons as suggested here. To illustrate this, let's look at a couple of simple code examples which are not necessarily specific to the a framework. The first is akin to using a singleton as a global object (i.e. bad):

    Actionscript:
    1. //EXAMPLE 1
    2. public class A
    3. {
    4.      public function setValue(val:int):void
    5.      {
    6.          MyModel.getInstance().value = val;
    7.      }
    8. }

    In the above example class A knows about the class MyModel and knows it's a singleton. We can't swap the singleton class for a subclass without changing code in class A.

    In the next example the class is not dealing with a singleton per-se, but a type:

    Actionscript:
    1. //EXAMPLE 2
    2. public class A
    3. {
    4.      private var _model:MyModel;
    5.      public function set model(m:MyModel):void
    6.      {
    7.           _model = m;
    8.      }
    9.  
    10.      public function get model():MyModel