Saturday 15 February 2048

Those elusive design patterns (part 3)

(continuation of part 2)
In our previous example I thought that the definition of ItemSelector was slightly contrived. Could we make it more general?

public interface Selector<X> {
 public void select(X select) ;
}

In that case the ItemChooser could look like :
public class ItemChooser extends Panel {
 ....
 public ItemChooser(ItemCatalog catalog, Selector<Item> selector) { ...

We could even try more parameterised code ... but this is beyond the point :
 public <X extends Item> ItemChooser(Catalog<X> catalog, Selector<? super X> selector) { ...

So this may lead to consider parameterised code for the Observer pattern :
public interface Observer<X> {
 public void update(X arg) ;
}

Then one could create either parameterised Subject :
 public void notifyObservers(X changed) ;

or "ad hoc" subjects pushing different data types :
 public void addThingObserver(Observer<Thing> obs)
 public void addItemObserver (Observer<Item> obs)

It's a choice: by controling more closely the type of the notification object we also loose generality.

But let's go back to our callback example. In the Pilot code :
public class Pilot extends  Panel implements Selector<Item> {

We still expose publicly some internal behaviour of Pilot which is it responds to a choice made by an inner component. We could hide this by creating an inner class implementing the Selector contract (or many inner classes implementing different Selector contracts) but the closure features enable somthing which is closer to the callBack notion:

public class Pilot {
   private ShowItem presenter= new ShowItem() ;
   private ItemChooser chooser ;
   ....
   public Pilot (Catalog <? extends Item> cat) {
       chooser = new ItemChooser(cat, {Item item => presenter.show(item); });
   }

and ItemChooser having :
 public ItemChooser(Catalog <? extends Item> catalog,
    {Item => void} action ) { ...

or some parameterised variant of it. Note that the decoupling is still better since the code which has the initiative of the call does not even need to know the name/purpose of the called method.

Now how about a Subject defined thus:
public class Dispatcher<X> {
   private ArrayList<{ X=> void}> actions = new ArrayList<{X=>void}>() ;
  
   public void addAction({X => void} action) {
       actions.add(action);
   }
  
   public void fire(X event) {
       for( {X=> void } func : actions) {
           func.invoke(event);
       }
   }
}

A funny twist could be added by making sure that every Observer code gets a different object as the result of the event! This could be through a Dispatcher<{=>Thing}> and it that case it's up to each observer to call the method that generates each distinct object. (another example: Dispatcher<{=>Iterator<Double>}>

It could be also through a method that guarantees that the generating method is called by the subject before any transfer to the observer:
   public void mapFire( {=>X } generator) {
       for( {X=> void } func : actions) {
           func.invoke(generator.invoke());
       }
   }

conclusions

  • - Revisiting the pros and cons of a pattern, browsing through the possible options and weighing the implementation choices will help both to match the implementation to your needs AND to reconsider your analysis through the light shed by the pattern's options . This a two ways process!

  • - Compare the initial UML schema and the latest codes for Dispatcher. This is to illustrate a principle: a design is not independent of the implementation language. Though we may try to design at a higher level of abstraction (and not deal with those pesky details of implementation) the paradigms of the implementation are still reflected at a higher level. You just can't have strategic thinking if you do not have some feedback from the field!
    (note : I even suspect some design patterns to be inherently implementable with interpreted languages -primary suspect: Visitor-)


(feb. 26 2008).

No comments:

About Me

My photo
to graduate at my architecture's school I wrote a thesis on "fuzzy" methods (that was in 1974). afterwards I turned software engineer (and later to java evangelist) but this just strenghtened my views on methods ... I'll try to share (though it is hard to write precisely on fuzzy topics). ...