Beware of singleton in Flex modules

Example 1 (without importing the singleton class in the main application – module-wide singleton):

Live demoSource code (LICENSE)

Example 2 (singleton class imported in the main application – application-wide singleton):

Live demoSource code (LICENSE)

This is something I recently discovered during some tests and it’s something to consider when using the singleton design pattern inside Flex modules. First of all, here is an example implementation of the singleton pattern in Flex:

public class SingletonClass
{
	protected static var _instance: SingletonClass = null;
	
	public static function getInstance(): SingletonClass
	{
		if (_instance == null)
		{
			_instance = new SingletonClass();
		}
		
		return _instance;
	}
}

This class can be simply used to get the singleton instance with a line like this:

var theInstance: SingletonClass = SingletonClass.getInstance();

This is what we already knew. But what could happen if we try to get a singleton instance inside a Flex module? It could happen that our SingletonClass represents in fact a singleton in two different ways: application-wide singleton or module-wide singleton. In the application-wide case, the instance of SingletonClass is unique across the entire application that uses some Flex modules, while in the module-wide case, the instance in unique only inside a single module, but different across different modules. This is really important to know because we may have undesired behaviors of our application and it could be difficult to figure out what happens without knowing this.

Now, the question is: how do we know when we have an application-wide singleton instead of a module-wide singleton? You may have guessed the answer from the examples links at the beginning of this post. We have an application-wide when the SingletonClass is imported in the main application while we have a module-wide singleton when the SingletonClass is used only inside the modules and never imported in the main application. An example will be useful to clarify everything.

To test the SingletonClass instances creation we need to modify a little bit the original class that we saw earlier.

public class SingletonClass
{
	protected static var _instance: SingletonClass = null;
	
	public static function getInstance(): SingletonClass
	{
		if (_instance == null)
		{
			_instance = new SingletonClass();
			
			// Generate a random instance ID
			_instance._instanceID = Math.round(Math.random() * 100);
		}
		
		return _instance;
	}
	
	protected var _instanceID: Number = NaN;
	
	public function get instanceID(): Number
	{
		return _instanceID;
	}
}

Each time a new instance of SingletonClass is created, we generate a random ID so we can identify it easily during our tests. A module in the test applications will look like this:

<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml">

	<mx:Script>
		<![CDATA[
			import com.devahead.misc.SingletonClass;
			
			[Bindable]
			protected var _instance1ID: Number = -1;

			[Bindable]
			protected var _instance2ID: Number = -1;
		
			protected function onGetInstance1BtnClick(event: MouseEvent): void
			{
				_instance1ID = SingletonClass.getInstance().instanceID;
			}

			protected function onGetInstance2BtnClick(event: MouseEvent): void
			{
				_instance2ID = SingletonClass.getInstance().instanceID;
			}
		]]>
	</mx:Script>

	<mx:Panel title="Module 1" layout="vertical"
		paddingTop="3" paddingBottom="3" paddingLeft="3" paddingRight="3">

		<mx:HBox verticalAlign="middle">
			<mx:Button id="getInstance1Btn" label="Get instance 1"
				click="{onGetInstance1BtnClick(event)}"/>
			
			<mx:Label text="Instance 1 ID:" fontWeight="bold"/>
			<mx:Label text="{_instance1ID}"/>
		</mx:HBox>
	
		<mx:HBox verticalAlign="middle">
			<mx:Button id="getInstance2Btn" label="Get instance 2"
				click="{onGetInstance2BtnClick(event)}"/>
			
			<mx:Label text="Instance 2 ID:" fontWeight="bold"/>
			<mx:Label text="{_instance2ID}"/>
		</mx:HBox>

	</mx:Panel>
	
</mx:Module>

Here we provide a couple of buttons to invoke two times the getInstance function of the SingletonClass and save the ID of the instance returned by the function. This is simply to show that in fact multiple invocations of the getInstance function return the same instance, so the SingletonClass is working properly.

In the example 1 we don’t import the SingletonClass so the main application looks very simple:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	pageTitle="Beware of singleton in Flex modules - devahead BLOG"
	layout="vertical" horizontalAlign="left"
	viewSourceURL="srcview/index.html">

	<mx:Label text="Push the buttons. The instance ID is different for each module."/>

	<mx:ModuleLoader url="com/devahead/modules/Module1.swf"/>	
	<mx:ModuleLoader url="com/devahead/modules/Module2.swf"/>	

</mx:Application>

To try it, just push the buttons in the different modules and you’ll see that the IDs of the instances are different. Now let’s take a look at the example 2. Here we actually do the same thing that we do in the modules, so we use the getInstance function to obtain instances of the SingletonClass hence the type is imported also in the main application.

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	pageTitle="Beware of singleton in Flex modules - devahead BLOG"
	layout="vertical" horizontalAlign="left"
	viewSourceURL="srcview/index.html">

	<mx:Script>
		<![CDATA[
			import com.devahead.misc.SingletonClass;
			
			[Bindable]
			protected var _instance1ID: Number = -1;

			[Bindable]
			protected var _instance2ID: Number = -1;
		
			protected function onGetInstance1BtnClick(event: MouseEvent): void
			{
				_instance1ID = SingletonClass.getInstance().instanceID;
			}

			protected function onGetInstance2BtnClick(event: MouseEvent): void
			{
				_instance2ID = SingletonClass.getInstance().instanceID;
			}
		]]>
	</mx:Script>

	<mx:Label text="Push the buttons. The instance ID is the same for each module and the main application."/>

	<mx:Panel title="Main application" layout="vertical"
		paddingTop="3" paddingBottom="3" paddingLeft="3" paddingRight="3">

		<mx:HBox verticalAlign="middle">
			<mx:Button id="getInstance1Btn" label="Get instance 1"
				click="{onGetInstance1BtnClick(event)}"/>
			
			<mx:Label text="Instance 1 ID:" fontWeight="bold"/>
			<mx:Label text="{_instance1ID}"/>
		</mx:HBox>
	
		<mx:HBox verticalAlign="middle">
			<mx:Button id="getInstance2Btn" label="Get instance 2"
				click="{onGetInstance2BtnClick(event)}"/>
			
			<mx:Label text="Instance 2 ID:" fontWeight="bold"/>
			<mx:Label text="{_instance2ID}"/>
		</mx:HBox>

	</mx:Panel>

	<mx:ModuleLoader url="com/devahead/modules/Module1.swf"/>	
	<mx:ModuleLoader url="com/devahead/modules/Module2.swf"/>	

</mx:Application>

Pushing all the buttons, you can verify that the instance ID is always the same both in the main application and the modules. This is really important to know every time you work with the singleton pattern and the modules.

Comments

Josh
Reply

Hey man,

Just wanted to say: Nice post! I’ve been working with these concepts in flex… this cleared up quite a bit for me.

It’s nice when experienced developers share their knowledge like you. Really helps out the community.

Josh
Reply

opps! I typed “Hey man” out of habit :-) More like “Hey Ma’am”! Sorry ’bout that!

Andrea Bresolin
Reply

I’m glad you found the post useful. I wish I had much more time to write some new posts.

Venkat
Reply

Awersome !!!!!.

Nick
Reply

Hi:
please help me to solve The singleton problem.
My case is same as moudle wide singleton.(in module create singleton)
But the result is like application wide singleton.
two singleton become to same object.
It’s serious problem to me.(must be seperated)
Help me please! thanks.

Leave a comment

name*

email* (not published)

website