Saturday 15 February 2048

Those elusive design patterns (part 2)

It may sound strange to talk about programming design patterns in a "fuzzy" methods context.
There are two reasons for that:
  • - Though the inner mechanisms of programming patterns are well described their scope must be subject of very thorough discussions. In that sense I often say that design patterns are more "inspirational paths" than precise recipes.
  • - This notion of a structure that guides a search path has wider applications.
The initial descriptions of design patterns are accompanied by rationales and precise guidelines about their use and limits. Funnily if you browse the web those discussions tend to disappear: while focusing on the essence of the pattern most descriptions tend to forget those guidelines! The result is that we tend to be lazy or, even worse, use code generators once we have identified a pattern. As we profit from the work of our elders we forget about the precautions for use, we forget about re-enacting the logical build of the pattern. I am not talking about reinventing the wheel every time but about quickly following their path and profit from their experience ... which is different from applying indiscriminately a recipe.
Let's revisit a well known pattern which is Observer.
I have not found in line the precise description as in GOF (so for the moment just a concise description here )
Now compare the GOF description with the Java implementation of Observer/Observable:
public class Observable { // the "subject"
   // details skipped here
   // including interesting case of setChanged()

   public void addObserver(Observer o)  { .....

   public void notifyObservers(Object arg) { ....

public interface Observer {
   public void update(Observable o, Object arg) ;
}
Though many people argued against Observable being a class (and not an interface) I would rather focus on other additional remarks here :
  • - Java has opted for a "push" option : the Observer does not have to go after the subject to request state information. The notification object could be anything (including something that may enable the Observer to request back some state information!).
  • - Implicitly the Observer here can register itself to different subjects. Other implementation of this pattern may skip this ability.
  • - The "contract" for an actual Observer should specify more contraints. A common example is that each update method should terminate as quickly as possible to avoid blocking further notifications to other Observers. One could implement a different set of Observer/Observable where there is a different Thread to handle each notification (or anything that could make the notification asynchronous -we are here slipping towards a publish/subscribe pattern-). Note that abnormal termination of update should also be handled gracefully (that is: if a Throwable is creeping up the stack the Subject should not crash).
  • - Another twist to the story is illustrated by the event mechanism in AWT: when notifications are fired in rapid bursts there could be a merging of events in an event queue.
  • - The fact that Observer is an interface is an illustration of the decoupling principle. This can be illustrated with the example of the call-back pattern: Object of type O is registering itself with object of type S that will call back later. Since O "knows" S and S keeps a reference to O there would be a cyclic dependency of types if O were not an interface. This pattern can be considered as a simplified Observer case: there is only one Observer.
Let's have a look at a use of this simplified pattern ... this will lead us to further versions of the Observer:
Suppose we are desiging a GUI where there is a Component that helps the user to choose an Item and another Component which is able to show the details of the Item.
public class ShowItem extends Panel {
   .....
   public void show(Item choosen) { ....
}
Then the ItemChooser Component:
public class ItemChooser extends Panel {
   ....
   public ItemChooser(ItemCatalog catalog, ItemSelector selector) { ...
}
When the user picks up an Item with the help of the ItemChooser then another code will be notified. The reference to this code (ItemSelector) should be an interface, then
public class Pilot extends Panel implements ItemSelector {
   // this component has a Controler role
   // create subComponents of type ItemChooser and ShowItem
   private ShowItem presenter;
   private ItemChooser chooser ;

   public Pilot(ItemCatalog catalog) {
       chooser = new ItemChooser(catalog, this) ;
       presenter = new ShowItem() ;
       ...
   }

   // the contract of ItemSelector
   public void select(Item choice) {
       presenter.show(choice) ;
   }
   ...
}
Here we could not design an ItemChooser(ItemCatalog, Pilot) otherwise we will get a strong coupling between the Pilot and ItemChooser classes.
This said the ItemSelector definition is slightly contrived: can we make it more general, more "pattern like"? This will lead us to reconsider the more general Observer pattern.
More to come ....

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). ...