A Webpublisher Xml class library and polymorphism

by Peter Tyrrell Thursday, February 14, 2008 4:26 PM

Last fall I wrote a new class library to handle Inmagic Webpublisher XML API calls with elegance and grace. That was the motivation anyway. One might well grasp the wind with chopsticks.

Each XML request type (query, insert, update, etc.) has some mandatory elements (e.g. textbase) and some optional elements (e.g. sort fields), so I used the Decorator Pattern to attach optional bits. The pattern provided the solution I was looking for, but threw me roughly into the world of OOP inheritance and polymorphism, where I felt at every turn like a man lost in a thorny thorn field without his pants.

I just found a way to remove a particularly sharp and prickly thorn.

The problem - Unable to access properties specific to a derived class

Consider this snippet of code:

// XmlInput is abstract base class, XmlQuery is derived from XmlInput
XmlInput query = new XmlQuery(tn, commandQuery, page, mr);
// Decorator wraps an XmlInput object
query = new SortFieldsDecorator(query, "Name|Product_Number".Split("|".ToCharArray()));

It's classic Decorator. The query object is at all times an XmlInput (the base class) type. You can pass it in to multiple decorators, and because it was instantiated as an XmlQuery, a class that derives from XmlInput, it gets some special XmlQuery-specific behaviour too (e.g. commandQuery, page, mr).

Trouble is, because the query object must be passed to decorators as XmlInput, there is no way to access the XmlQuery-specific public members:

// Cannot access XmlQuery-specific CommandQuery property! This doesn't work:
query.CommandQuery = "find blah =blah";

One consequence of this for me was that the derived classes such as XmlQuery had to jam every conceivable property into the constructor as a parameter, because they couldn't be set after the object was initialized. Not so bad with XmlQuery, as it happens, but a nightmare with XmlBatchModify which has many many properties:

// OMG!!! That's not even all of them!
public XmlBatchModify(string textbase, string password, ValidationType validation, BatchModifyActionType batchModifyAction, BatchModifyEntryType batchModifyEntry, bool matchCase, bool matchWholeWord)
{
}

Clearly something had to be done.

The fix? - Casting derived classes to base classes

I can go with the XmlQuery derived class from the get-go, set public properties after the constructor is called, and then cast the query object to the XmlInput base class before passing it to a decorator:

XmlQuery query = new XmlQuery(tn, commandQuery, page, mr);
// Now I can access XmlQuery-specific CommandQuery property
query.CommandQuery = "find blah =blah";
// Cast query object to XmlInput
XmlInput q = (XmlInput) query;
// Decorator accepts 
q = new SortFieldsDecorator(q, "Name|Product_Number".Split("|".ToCharArray()));

This works: properties specific to XmlQuery are not lost. I'm just not sure that it's entirely legal, or what consequences it may have in the long run.

 

blog comments powered by Disqus

Month List