"Because Design Patterns bills itself as being concerned with object oriented software alone, I fear that software developers outside the object community may ignore it. This would be a shame. [...] All software designers use patterns; understanding better the reusable abstractions of our work can only make us better at it." [ ]
Section | Pattern Name | Language | Description | |
---|---|---|---|---|
Use Case 1 | Chain of Responsibility | XQuery 1.0 | Send an HTTP request to create an Atom entry. | |
Use Case 2 | Translator | XQuery 1.1 | Transforms an Atom entry to XHTML. | |
Use Case 3 | Strategy | XQuery 1.1 | Store an Atom entry on the server. | |
Use Case 4 | Observer | XQuery 1.1 + Scripting | Advertise new Atom entries on Twitter. |
send-request
.
For example, a program that is sending a HTTP GET request to http://www.example.com could look as follows:
Reduce coupling between different modules by moving nested dependencies outside of a module and integrate dependent functions consecutively into a chain. Pass an item along the chain and give each of these functions the chance to manipulate or process the item.
local:post-entry
.
After this, we describe the two functions atompub-client:post
and http-auth:basic
.
Each of these functions takes as first parameter the request item which is prepared in the body of each function.
$request
) is declared and initialized containing the URL of the AtomPub server.
This element is passed along the chain of functions atompub-client:post
and http-auth:basic
ending up in a call to the http-client:send-request()
function.
The latter function takes over the responsibility of executing the request.
atompub-client:post()
"massages" the request item (using XQuery update) according to the AtomPub specification.
Specifically, this function makes sure that the HTTP request method is set to POST.
Moreover, it configures the body of the HTTP request to contain the entry to be published.http-auth:basic()
function adds username and password attributes to the request and sets the authentication method to basic
.
atompub-client:post
and http-auth:basic
) using the XQuery Update Facility.
Alternative implementations could copy and transform the request element and return it as a result of the function.
In this case, the client needs to make sure that the returned element is passed as an argument to the next function.http-auth:basic()
function with an appropriate function from a different authentication module.get-feed
function above by incorporating nested loops over elements in different namespaces.
However, this is not desirable for several reasons:
Separate interpretations of heterogeneous elements . Translator brings XSLT programming paradigm into XQuery.
apply
function: apply
function contains the code that does the transformation of an XDM instance if the match
function returned true.
The parameters of the apply
function are: (1) The XDM instance to transform, (2) the transform
function itself, and (3) the templates involved in the process.match
function: apply
function should be executed given a selected XDM instance.transform
function: transform
function is driving the transformation process (i.e. calling match
and apply
.
It is invoked by the client.match
and the second apply
function, respectively.transform
function by providing the XDM instance to be transformed and a sequence of templates.apply
and match
for Atom feeds and entries) need to know the Atom schema,
(2) the template responsible for transforming GeoRSS only knows the GeoRSS schema, and
(3) the transform
function orchestrates the transformation process by invoking the function items of the templates.
transform
function passing the XDM instance and the templates as parameters.
For each template, the transform
function first executes the match
function passing the current XDM instance as parameter.
If the result of the invocation of match
is true, then the apply
function is invoked on this instance.
Please note that the apply
function itself may repeatably invoke the transform
function to further transform nested structures.
transform
function which receives the XDM instance to transform (i.e. the Atom feed) and the transformation templates as parameters.
apply
and match
functions for all templates.
The example application contains templates for Atom feeds, Atom entries, and GeoRSS points.
For instance, it contains an xhtml-template
module which contains templates to transform Atom feeds and entries into XHTML.
Moreover, it contains a module to match and apply GeoRSS points.match
and an apply
function:
match-feed
and apply-feed
functions.match-entry
and apply-entry
functions.match-feed
and match-entry
are respectively checking if the XDM instance is an Atom feed or entry.
match
functions are associated to apply
functions, namely apply-feed
and apply-entry
.
Each of the apply
functions shown below is invoking the transform
function.
More specifically, in apply-feed
, the transform
function is invoked for each Atom entry in the feed.
In apply-entry
, the transform
function is invoked for all children of an entry.
If one of the children is contained in the GeoRSS namespace, it will be transformed by a matching template.
transform
function for the first time, passing as first argument an instance of an Atom feed to be converted and as second argument the templates as parameters.
transform
function can vary.
In our implementation, if the given input hasn't been matched by any template, it stops the process.
However, alternative implementation of the transform
function may look at the children of the XDM input.
apply
function invokes the transform
function, it may invoke it with a different implementation of the transform
function than the one received as parameter.
The same variation can apply for the templates passed as parameter to the transform
function.Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm implementations vary independently from clients that use it. [ ].
atompub:post
is called with the concrete filesystem storage strategy as parameter.atompub:post
function is responsible for creating a new Atom entry.
The create-strategy
argument is a function item that encapsulates the functionality to store an entry.
Therefore, it represents a concrete Strategy that stores the entry, for example in a collection.
Different concrete storage strategies are implemented within different modules that have no dependencies with the AtomPub server module.
For instance, atompub:post could use one of these strategies:
atompub:post
ContextFunction.
Finally, we will present the concrete implementation of the create
algorithm, i.e. a chosen ConcreteStrategy implemented in the store:create
function.atompub:post
passing store:create
as the chosen storage strategy.
atompub:post
shown below is processing an Atom entry posted by a client.
It takes three parameters: the feed uri, the entry to be aggregated, and the storage strategy.
First, the entry is processed.
Then it is passed as parameter to the invoked strategy function item.
create-strategy
algorithm to create an entry is implicitly defined as function(xs:string, schema-element(atom:entry))
.
Within XQuery there is no explicit mechanism to define an interface in the manner of an object oriented language like Java.
Therefore, one implicit way to define the common interface for the actual Strategy is by definition of the function item parameter within the signature of the ContextFunction.
store:create
function has to insert an atom:link
element into the feed metadata for each new entry which points to the according entry file.
if..then..else
statements to emulate configurability for different behaviors within functions. Such functions can be refactored using the Strategy pattern.Define a one-to-many dependency between functions so that when one is called, all its dependents are notified automatically [ ].
tweet-entry
function (the Observer).on-post
function is responsible for attaching new observers to the AtomPub server module (the Subject).
The AtomPub server is keeping track of all its observers with the on-post
module variable.
function(schema-element(atom:entry)) as item()*
.
The single parameter of the observer, (schema-element(atom:entry)
) is an instance of the Atom entry that has been created on the server.
tweet-entry
function is the Observer we will use in our use case: it will be executed for each new entry created on the server.
It takes an Atom entry as parameter and sends a message on Twitter with the following format: entry title, tiny url of the entry.
The function signature is compatible with the observer signature defined in the AtomPub server module (function(schema-element(atom:entry)) as item()*
).
tweet-entry
function as an Observer of the AtomPub server module.