Composition and recursive OCL

This article demonstrates a simple example of using recusive OCL within a composite pattern.

"To understand recursion we must first understand recursion" [Source unknown]

Surely there isn't a professional programmer out there who hasn't used recursion? I'd bet that the first recursive routine that most of those programmers wrote was some kind of FindAllFiles routine. The beauty of recursion is that it is so simple, yet the results give the illusion that the code must be far more complicated.

I'm slowly rewriting www.HowToDoThings.com in my very little spare time. Before the categorisation of articles was three levels deep, no more and no less; Topic->Category->SubCategory. One of the improvements I have decided to add to the site is the ability to nest an unlimited amount of levels. To do this I implemented a pretty basic OOP composite pattern like so

ClassDiagram

A "BaseCategory" is an abstract class, it's only purpose in life is to have a name and to own SubCategories. A "SubCategory" exists to own articles and more SubCategories. A "MainCategory" holds an image for the main page, and owns SubCategories. My categorisation can now consist of a minimum of two levels (MainCategory->SubCategory), or as many levels as I like.

Next, in the model's base class I implemented a derived attribute called "DisplayName: String". This attribute was initially added so that I could use a single web page ConfirmDelete.aspx to display the name of the object the user wants to delete (this would typically be an article, but I can reuse it for any object at all). The code for this attribute is as follows

public string DisplayNameDeriveAndSubscribe(
ISubscriber reEvaluateSubscriber,
ISubscriber resubscribeSubscriber)

{

IOclService ocl = (IOclService) this.AsIObject().


ServiceProvider.GetEcoService(typeof(IOclService));

return (string) ocl.EvaluateAndSubscribe(
this.AsIObject(), "self.asString",
reEvaluateSubscriber, resubscribeSubscriber).AsObject;

}

It merely evaluates "self.asString" against the current instance. This has the effect of evaluating the DefaultStringRepresentation OCL expression entered in the model and returning it as a string. BaseCategory has its DefaultStringRepresentation set to "name".

Now here is where the recursion comes into it. As I was entering a new SubCategory it didn't take long to realise that "ASP.NET" told me nothing about where in the categorisation structure I was working. Wouldn't it be nice if instead of just seeing "ASP.NET" I would actually see "Computers->Programming->Delphi 2005->ASP.NET"? So that's what I did, and the beauty is that it didn't take a single line of code to work out the path, because I used a very simple recursive OCL expression.

I added a new "Path: String" attribute to the SubCategory class, set Derived to True, and then set the Derivation OCL to "parentCategory.displayName". Remember that DisplayName will just return the Default String Representation, so in this case the SubCategory.Path is just returning the DisplayName of its parent. This isn't any use at all, until you change the Default String Representation too, like so...

parentCategory.asString + '->' + name

The DisplayName of any category is its parent's Default String Representation + a separator + its own name. What is its parent's Default String Representation? Well, if the parent is a MainCategory then the expression "name" is used, however, if the parent is also a SubCategory then the expression "parentCategory.asString + '->' + name" is used - all the way up until we reach the MainCategory.

Not only does this give me a very informative Path attribute, but as a very pleasant by product, it also gives me the full path + name in the ConfirmDelete.aspx web form whenever I try to delete a SubCategory object.

 

Share this article!

Follow us!

Find more helpful articles: