PDA

View Full Version : Enforce usage of another class through interface.


wvxvw
09-09-2009, 07:25 PM
I think my question will best fit here because it's more architectural then coding.
Prerequisites first:
- IStyleClient (an interface that should enforce the usage of StyleManager).
- StyleManager (a centralized storage for CSS-like styles + an instrument for setting styles on StyleClient[s]).
- A variety of StyleClient (These classes need to be styled).

Dilemma: I would prefer to make it so that by implementing the interface, the clients would:
- enforce importing StyleManager (this is easy).
- embedding themselves into StyleManager's tree of clients (i.e. styles may be inherited through parent-child chain).
- be notified when their style changes.
- provide API for changing their style whilst notifying StyleManager.

I know this mechanism exists in Flex framework, and I know at an average-good level how it works, but I would like to make it more logical and efficient if possible.

So, I was thinking about something like this:
if I have a method in the IStylable
function setManager(manager:StyleManager):void;
Assuming the developer would add listener to StyleChangeEvent dispatched from the manager and notify the manager back, when the style is changed, I feel like I'm giving to much freedom to the 3rd-party developer, that may also not know he should do the above...

Another way of doing the same thing is like so:
package com.aditall.styles
{
import flash.events.IEventDispatcher;

[Event(name="styleChange", type="com.aditall.styles.StyleChangeEvent")]
[Event(name="stylePropertyChange", type="com.aditall.styles.StyleChangeEvent")]

/**
* ...
* @author wvxvw
*/
public interface IStylable extends IEventDispatcher
{
function get styleName():String;
function get styleID():String;
function get stylableParent():IStylable;
function get stylableChildren():Vector.<IStylable>;
function get style():Object;

/**
*
* @param parent
* @param theStyle
* @param children
* @return This function will be called on style or property change.
* It must have the following signature:
* <code>function(property:String, oldValue:*, newValue:*):Boolean</code>
* This function should return <code>true</code> if the property change marks
* parent as "dirty" and false otherwise.
*/
function appendToChain(parent:IStylable, theStyle:Object,
children:Vector.<IStylable>):Function;
}

}
I cannot tell it looks any better to me, besides, id doesn't enforce StyleManager import.

I hope I explained it, but, if I didn't... I'll be happy to add more info. And if there is a common way to do such thing, I'd like to read about it, but, I think I just don't know how to call this, so, google / wiki aren't helpfull quite as much this time :)

bowljoman
09-09-2009, 08:53 PM
I would use a base class and require the client to extend the base class. I would handle all the StyleManager stuff in the base class.
Do you require the client to be notified on change? I prefer implementing the 'client' model that netstream uses for onMetaData() and onPlayStatus(); and require a client object in the base Class constructor. Throw a runtime error if the client is null.

bowljoman
09-09-2009, 08:57 PM
By baseclass, the client would 'override' the behavior rather than 'implement' the behavior.

bowljoman
09-09-2009, 09:21 PM
Sneak an import of StyleManager into the StyleChangeEvent.

wvxvw
09-09-2009, 09:34 PM
Yeah, that's also is a Flex framework pattern, but I find it not perfect when you have to deal with other classes, which do not extend the client and you need to use composition (which is a waste IMO).
But I can see what you mean when you mention NetStream... I was thinking about making it like EventDispatcher(IEventDispatcher) - however, this would be composition again...

Besides, I really want the StyleManager to do the job / logic, not the clients... So that for example if some particular client fails to do what it's supposed to, I would be able to handle that in the manager, and this won't affect other "normal" clients.
Like, imagine situation when someone overrides Event.clone() like so:
public override function clone():Event { return null; }
So, if I have control over EventDispatcher, I may check if the cloned event is null and "forget" the damaged event.
I.e. EventDispatcher <--> Event relationship would be ideal in my case. Meaning, the StyleManager as EventDispatcher, and the Client as Event. With the only difference, there should be IEvent instead :)

wvxvw
09-09-2009, 09:43 PM
Sneak an import of StyleManager into the StyleChangeEvent.

Wow, this is something I haven't thought about :) Actually, sounds smart. So... I would for example make Client dispatch "I'm invalid" event, and that would automatically inform the StileManager, there is a chain to validate, no matter where it is :) Besides, since I have a reference to the Event's target I may find the "invalid" client too... hm...

yell0wdart
09-09-2009, 10:27 PM
Basically using an Observer (http://en.wikipedia.org/wiki/Observer_pattern) of sorts... Sounds pretty slick so far. Let us know how it goes. :)