At 12:51 PM 4/23/2001 -0700, Terrel Shumway wrote:
>JSP,PSP, BuildKit and just about any other tool that references files,
>eventually invents a Context object that will (among other things) bind a
>name (path, relative or otherwise) to a resource (file) when
>requested. serverSidePath is a start, but it is far from suitable for the
>requirements of a template engine. Adding caching, variant bulids, and
>libraries (important features for a non-toy template engine) quickly
>increases the complexity of the binding process. Making the Context a
>first class citizen, (rather than a second-class method) helps it get the
>attention it deserves in the system design. Also, a Context almost always
>follows a composite pattern, able to create and reference contained
>contexts by name.
I have avoided contexts in my designs for a couple reasons. One is that
that contexts I have seen look like a hodge podge of "we don't know where
to put foo, so we'll just stick it here."
The other problem has to do with independence. If Context is a WebKit thing
and "TemplateKit" depends on it, then you can no longer use TemplateKit by
itself. If both WebKit and TemplateKit have their own Contexts then there
is conceptual difficulty in determining where to put TK's Context in WK at
run time and how the 2 are related, if at all.
I learned a design approach from NeXTstep called "delegation" which worked
really well. That term gets used for more than one thing, especially in the
OOP world, so let me expand.
First you can find a high level description at:
"Delegation is a reuse concept that emphasizes cooperation over
specialization. One common problem facing developers is intervening in the
middle of some operation performed in third party code. For example, you
may find everything about a third party method fine except that some other
operation in your program really ought to be executed, checked, or aborted
depending on how the third party method is proceeding.
Usually the solution is to rewrite the third party method from scratch in a
subclass. This may sound straightforward but it usually isn't. The most
obvious problem is that you are now creating another class that you'll have
to maintain. But what's worse is that you are inviting disaster because you
don't necessarily know enough about the class in question to understand the
"context" of the method you want to override in your subclass (such as the
beginning and end conditions on a while loop).
If you have source code, you can use that to write your method to set up
the loop properly - but this violates encapsulation and ties your code to
the third party's implementation. If you don't have source code, you can
pretty much forget about being able to override the method successfully
except by pure luck. This is one of the classic problems with
Enter Delegation. A Delegate is nothing more than a dynamically bound and
typed object used often in the implementation of Objective-C classes. The
delegate can be any object, perhaps a central controller object or a
business object. Third party objects can send messages to their delegate at
appropriate times (such as within a while loop or right before one) giving
the delegate the opportunity to approve, reject, customize, or simply
become synchronized with what's happening in the third party object. Many
OPENSTEP classes use delegation. For instance an NSWindow object may have a
delegate assigned that gets informed whenever the window is dismissed or
asked for approval right before the window is closed. Another type of
delegate method is one that assigns a specific task to the delegate such as
handling a particular operation in total. For example, an instance of the
EODisplayGroup class asks its delegate to filter and sort its array of
Enterprise Objects fetched from a database."
In Python, you would have these methods:
def setDelegate(self, delegate):
self._delegate = delegate
Then you would advertise what things you expect that the delegate and can
provide or be notified about:
Delegates can implement 'templatePath()' to take a relative path
and produce an absolute path where the template can be found. The method
may return None if the template does not exist.
If there is no such delegate method, the current working directory
Later in your code:
def templatePath(self, path):
if hasattr(self._delegate, 'templatePath'):
The point here is that any object in your system can intervene by becoming
the delegate of the template manager. It doesn't have to be a particular class.
Also, each class that uses delegates can advertise exactly the delegation
features that are appropriate.