Monday, October 15, 2007

Delegate Factories with Prana

I've been having fun with Prana lately. Prana is an IoC container framework for Flex under development by Christophe Herreman. Prana is sort of built with Cairngorm in mind, but it could work for any configuration and injection you wanted to do at runtime.

One of the benefits I can see is for rapidly prototyping an application with little to no knowledge of the service you may need to connect to for your data needs. If you can define the data model well enough, you could build your application with Cairngorm in such a way that all you'd need to do is change one file (or type of file): the Delegate.

That's the reason for the business delegate: to keep the application isolated from the implementation of the service layer.

I've written up an example of how I'm currently using this on a project and posted it at http://labs.effectiveui.com/examples/prana/delegates/. It's a pretty lame sample, but if you right click and select "View Source", it shows how I have created a DelegateFactory that gives my commands a Delegate that conforms to a certain interface. Then, using Prana, I can configure the DelegateFactory to build whichever implementation of the Delegate I wanted, without recompiling the application.

The benefit is that I can drive the application's data from dummy xml data, but the application doesn't care where that data comes from. As long as I'm write about the way the data looks, my Commands don't need to change once I switch over to a production ready Delegate.

First, look at the DelegateFactory. Notice that it contains a string, _delegateClassName which will contain the qualified name of the class I want the DelegateFactory to make. There's some type-checking in there once that string is set to make sure that points to a class that conforms to the interface. One last thing to notice is that I need to have the class of the delegate referenced at least once in the code so that it's compiled in. That happens on the line that says

private static var compileTheseClasses:Array = [DevDelegate]


So DevDelegate is the delegate I want to use at development time. That Delegate acts like a regular delegate that calls an HTTPService to get some xml. Instead of doing that, though, it just loads xml local to the swf and sends a ResultEvent to the LoadPeopleCommand as if a result had just returned from the HTTPService.

Once last thing to notice is the applicationConfig.xml which drives Prana. It's loaded by the InitializeCommand. In that first block there:

<object id="delegateFactory" class="com.effectiveui.examples.business.DelegateFactory" factory-method="getInstance">
<property name="delegateClassName" value="com.effectiveui.examples.business.DevDelegate" />
</object>


I tell Prana to configure my DelegateFactory with the delegate class I want to use. I can change this xml file at runtime, so as long as I make sure the Delegate is compiled in, I can change delegates whenever I need.

Of course that's just one of the uses of Prana, but I really like the ability to get up and running easily by making a development time delegate.

4 comments:

dobie said...

I like the example except for the delegate sending back the results of the urlloader to the command. I've found it much easier to create the class object in the delegate so that the command doesn't munge any of the data itself. That way, your commands always are dealing with class objects.

Also, this example only shows how to use one delegate. I tend to have one event per command per delegate. So, how would I use Prana to have multiple delegates? Would I need to have a method in the DelegateFactory per delegate? Then define that delegate in the applicationContext.xml?

Tony said...

@dobie Your point about commands just dealing with xml is well taken. In most cases I like to do what you said and keep the munging out of the command. Notice though, that the command only expects XML, it doesn't do anything with it. It's the responsibility of the VO to translate from XML. I do that when expecting XML since it's easier to keep track of the translation code.

For your second point, you could do one of two things: 1.) Have a getter method for each type of delegate on your factory and configure all the types of the delegates from prana, or b.) Have a factory for each type of delegate. Obviously 1 sounds a little cleaner.

I'd suggest that you consolidate delegates, though. I like to consolidate delegates around a "resource", which generally corresponds to an entity. That usually leaves me with more than one delegate, but considerably less than one delegate per command.

Tony said...

@dobie In looking at the command again, it could benefit from knowing less about the XML.

Mark said...

This example has certainly given me some inspiration - thank you. But I have similar requirements to dobie - I have multiple delegates and do not want one factory per delegate but a factory that can access all the delegates.

So instead of using a property for 1 single delegate, I have used an object property to hold multiple delegates and provided a getDelegate method on the factory.

Thanks very much