Building a Settings Framework


In this next example we'll build a simple application that uses a Singleton class called Settings to hold global values.

The Settings class loads data from an XML file at runtime and provides access to its values. It's a simple concept, but it's very useful to be able to change these settings without recompiling the application.

Creating the XML Document

The XML document for this framework is simple. We have a settings root node that contains multiple property nodes. Each property node has an id and a value attribute. The Settings class does a lookup on the id attribute and returns the value attribute. The following is the XML document, titled config.xml, which we'll use in this example:

<?xml version="1.0" encoding="UTF-8"?> <cs:settings xmlns:cs="http://www.dannypatterson.com/2006/ConfigSettings">    <cs:property  value="This is the first test value." />    <cs:property  value="This is the second test value." /> </cs:settings>


Note that we added a namespace to this document to demonstrate how simple namespaces are to use inside E4X. For more information on XML namespaces, see Chapter 15, "E4X (XML)."

Creating the Settings Class

Now you'll need to create a new ActionScript class named Settings and put it in the com.peachpit.aas3wdp.singletonexample package. It has three main responsibilities:

  • It follows the Singleton design pattern; therefore, it manages its creation and access the same way as the previous example.

  • The Settings class also provides access to the values in the XML file through simple property access, like this:

    var myString:String = Settings.getInstance().testOne;

  • Because testOne isn't a property of the Settings class, we have to allow the request to come in and capture it. To enable this functionality we need to make the class dynamic so that other classes can call undefined properties. To capture these undefined requests, we'll subclass the built-in flash.utils.Proxy class and override the getProperty() method.

    Extending Proxy

    To gain the Proxy functionality we must subclass it and override the getProperty() method. This is a little tricky because the Proxy class' getProperty() method exists inside the flash_proxy namespace. For more on using the Proxy class, check out Chapter 6, "Proxy Pattern."


  • Because this class loads an external XML file, it must have a method for loading that file and an event that is dispatched when the file has loaded successfully. To enable the class to dispatch events, we will use the built-in EventDispatcher class.

Adding Eventdispatcher Functionality Through Composition

Because we have to subclass Proxy to use its functionality, and because ActionScript allows only for single inheritance, we must add the Eventdispatcher functionality through composition by implementing the IEventDispatcher interface. For more on Eventdispatcher and IEventDispatcher, see Chapter 13, "Working with Events."

[View full width]

package com.peachpit.aas3wdp.singletonexample { import flash.events.Event; import flash.events.EventDispatcher; import flash.events.IEventDispatcher; import flash.net.URLLoader; import flash.net.URLRequest; import flash.utils.Proxy; import flash.utils.flash_proxy; dynamic public class Settings extends Proxy implements IEventDispatcher { static private var _instance:Settings; private var _eventDispatcher:EventDispatcher; private var _data:XML; private var _isLoaded:Boolean; private var _urlLoader:URLLoader; static public const INIT:String = "init"; public function get isLoaded():Boolean { return _isLoaded; } public function Settings(enforcer:SingletonEnforcer) { _eventDispatcher = new EventDispatcher(); _isLoaded = false; } private function onXMLDataLoaded(event:Event):void { _data = XML(_urlLoader.data); _isLoaded = true; dispatchEvent(new Event(Settings.INIT, true, true)); } public static function getInstance():Settings { if(Settings._instance == null) { Settings._instance = new Settings(new SingletonEnforcer()); } return Settings._instance; } flash_proxy override function getProperty(name:*):* { var cs:Namespace = _data.namespace("cs"); var qname:String = String(name); return _data.cs::property.(@id == qname).@value; } public function loadSettings(url:String):void { var urlRequest:URLRequest = new URLRequest(url); _urlLoader = new URLLoader(); _urlLoader.addEventListener(Event.COMPLETE, onXMLDataLoaded); _urlLoader.load(urlRequest); } public function addEventListener(type:String, listener :Function, useCapture: Boolean = false, priority:int = 0, weakRef: Boolean = false):void { _eventDispatcher.addEventListener(type, listener, useCapture, priority, weakRef); } public function dispatchEvent(event:Event):Boolean { return _eventDispatcher.dispatchEvent(event); } public function hasEventListener(type:String):Boolean { return _eventDispatcher.hasEventListener(type); } public function removeEventListener(type:String, listener :Function, useCapture: Boolean = false):void { _eventDispatcher.removeEventListener(type, listener, useCapture); } public function willTrigger(type:String):Boolean { return _eventDispatcher.willTrigger(type); } } } class SingletonEnforcer {}



XML Usage (E4X)

Inside the getProperty() method, we used the new E4X functionality to pull the data out of the XML object based on the name of the requested property. For more on E4X, check out Chapter 15, "E4X (XML)."


Invoking the Settings Class

Next, we'll need a main class for the application in order to utilize the Settings class. We'll call the main class SettingsExample, and define it as follows:

package {    import com.peachpit.aas3wdp.singletonexample.Settings;    import flash.events.Event;    import flash.display.Sprite;    public class SettingsExample extends Sprite {       public function SettingsExample() {          Settings.getInstance().loadSettings("config.xml");          Settings.getInstance().addEventListener(Settings.INIT, onSettingsInit);       }       private function onSettingsInit(event:Event):void {          trace(Settings.getInstance().testOne);          trace(Settings.getInstance().testTwo);       }    } }


This class is the start of the project. It retrieves the singleton instance of Settings, then it displays the values from the dynamic properties. In the constructor, we first get a reference to the single instance using the static getInstance() method. Then we call the loadSettings() method and add the Settings.INIT event listener.

Inside the onSettingsInit() event handler, we trace the value of testOne and testTwo from the Settings instance. These variables are not actually properties of the Settings class. You'll see later in this example that the Settings class uses a new feature of ActionScript 3.0 called Proxy to handle this request and return the value from the XML document.

Now you can debug the project. You should see the values of properties testOne and testTwo being displayed in the trace console.




Advanced ActionScript 3 with Design Patterns
Advanced ActionScript 3 with Design Patterns
ISBN: 0321426568
EAN: 2147483647
Year: 2004
Pages: 132

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net