Archive for October, 2006

Design pattern wanted.

Calling all design pattern gurus. I’ve got a challenge for all you object orientated persons. I’m currently working on an actionscript component framework, that includes modal behaviour. That is if a component is modal, when it is enabled, all other components are disabled. Think of an alert box that doesn’t allow you to progress through an application until you’ve chosen an option and you’ll see what i’m trying to achieve.

I’ve actually got this all working fine. My only reservation is that the solution i’ve come up with seems a bit clunky. Anyway on with the show. I’ll detail all the steps in the creation, with pseudo-code examples.

The basis for all this is the component class, which all my other components will inherit from. It has enable, and disable public functions.

class com.lookmum.view.Component{
//enable function
public function enable(){
//enable component code here
}

//disable function
public function disable(){
//disable component code here
}
}

Next comes the creation of the modal manager class. This is a singleton which all components will register with when they become enabled, and unregister from when disabling. It also includes methods to enable and disable all active components. Here’s the relevent parts of the class shown with pseudo-code

class com.lookmum.util.ModalManager
{
// the list of all enabled components
private var componentList : Array
//the list of all components that this class has disabled, stored ready for re-enabling
private var disabledList : Array
public function registerComponent (com : Component) : Void
{
//add a component to the active list
}
public function unregisterComponent (com : Component) : Void
{
//remove a component from the active list
}
public function disableModal () : Void
{
//disable all active components and add them to the disabled list
this.disabledList.push ([])
var currentLayer : Number = this.disabledList.length - 1
<![CDATA[for (var i = 0; i < this.componentList.length; i ++)]]-->
{
if (this.componentList [i].enabled)
{
this.componentList [i].disable ()
this.disabledList [currentLayer].push (this.componentList [i])
}
}
}
public function enableModal (forceAll : Boolean) : Void
{
//enable the last disabled batch of components and put them back into the enabled list
var currentLayer : Number = this.disabledList.length - 1
var currentLayerLength : Number = this.disabledList [this.disabledList.length - 1].length
<!--[CDATA[for (var i = 0; i < currentLayerLength; i ++)]]-->
{
this.disabledList [currentLayer][i].enable ()
}
this.disabledList.pop ()
}
}

We then revise the component class to register itself with the singleton on enable, and unregister on disable.

import com.lookmum.util.ModalManager
class com.lookmum.view.Component{
private var modalManager:ModalManager
//constructor function
public function Component(){
//get a reference to the modal manager singleton
this.modalManager = ModalManager.getInstance()
}
//enable function
public function enable(){
//register the component with the modal manager
this.modalManager.registerComponent(this)
//enable component code here
}
//disable function
public function disable(){
//unregister the component from the modal manager
this.modalManager.unregisterComponent(this)
//disable component code here
}
}

Our immediate problem is that the enable functions affect registration with the singleton, so we need to test wether it is the singleton doing the enabling, and not to register/unregister if it is. The quickest thing to do is to pass an argument to the enable functions telling the component that the function is being called by the manager.

//the modified enable modal function in modal manager
public function enableModal (forceAll : Boolean) : Void
{
//enable the last disabled batch of components and put them back into the enabled list
var currentLayer : Number = this.disabledList.length - 1
var currentLayerLength : Number = this.disabledList [this.disabledList.length - 1].length
<!--[CDATA[for (var i = 0; i < currentLayerLength; i ++)]]>
{
this.disabledList [currentLayer][i].enable (true)
}
this.disabledList.pop ()
}

and…

//the modified enable function
public function enable(modal:Boolean){
if(modal){
//register the component with the modal manager
this.modalManager.registerComponent(this)
}
//enable component code here
}

The main problem with this approach is that we are making what should be internal behaviour public. There’s no way to enforce that the boolean value will only be passed by the manager.

Another approach would be to have a pair of enable functions, enable() and modalEnable(). One for general use which performs the registration, and one for use by the manager. However this still makes public something that should happen behind the scenes. There’s nothing to stop another developer accidentally using modalEnable() instead of enable()

The solution I came up with was to have this second enable function, but make it a private member. I then create a function delegate within the normal enable function and pass it to the modal manager with the component registration.

//the modified enable function
public function enable(){
//register the component with the modal manager and pass a function delegate as a scond parameter
this.modalManager.registerComponent(this,mx.utils.Delegate.create(this,this.modalEnable())
}
doEnable()
} 	private function doEnable(){
//enable component code here
}

We then give the manager event dispatching behaviours and let it add and remove the listeners itself.

public function disableModal () : Void
{
this.disabledList.push ([])
var currentLayer : Number = this.disabledList.length - 1
var dispatchList:Array = new Array()
for (var i = 0; i < this.componentList.length; i ++)
{
if (this.componentList [i][0].enabled)
{
dispatchList.push(this.componentList [i][1])
this.disabledList [currentLayer].push (this.componentList [i])
}
}
for (var i:Number = 0; i
this.addEventListener(DISABLE,dispatchList[i])
}
this.dispatchEvent(new Event(DISABLE,this))
for (var i:Number = 0; i
this.removeEventListener(DISABLE,dispatchList[i])
}
}

What i really want is some way to make a method of a class A only available to instances of another class B, bearing in mind that these two classes are unrelated, and i want any errors to be compile time, which means doing fancy things with arguments.caller isn’t quite what i want.

Any ideas anyone, or am i just being a pedant?

5 Comments


Particle Playground

I finally released my finished particle simulation extension for flash7+. You can purchase it from flashden here for a mere 10 bones.

No Comments


Featured item on flashden (with thoughts on wallop)

A simple little extension I created for flashden is currently a featured item. This site rocks. It allows me to package up little utilities i created for other jobs and sell them for a few bucks without the hassle of setting up my own on-line store.

This got me thinking about microsofts new myspace competitor wallop. A few people have pointed out that you can make quick cash from creating little widgets for the site. But i wonder if this is really such a great idea. The fact that you need to invest the development time for such items, coupled with the rather large API you need to learn in order to implement widgets for the site, seems to suggest that you need to ship a lot of units before you see any return on the time you’ve invested. And i’m not event sure how many people are actually using wallop.
Compare this to flashden where all i have to do is package things i’ve already developed, and i think it’s easy to see that there’s better ways to spend your time.

2 Comments



  • SetPageWidth