Castle And The Open/Close principal
Recently I have been trying to use Castle Windsor to make me a cup of coffee. So far I managed to gray screen the coffee machine, but I am okay with this limitation, since it is just about the only thing that I can't do with it.
The scenario, I have a set of similar services that I want to load from configuration. They all implement the same class, but have different configuration, here is a sample:
My first attempt to solve this issue was with this configuration:
<properties>
<customers.web.service.url>/customers.aspx</customers.web.service.url>
<customers.web.service.start>/customers.aspx</customers.web.service.start>
<customers.web.service.end>/customers.aspx</customers.web.service.end>
</properties>
And using it like this:
<component id="customers.web.service" type="my.web.service, sample">
<parameters>
<url>${customers.web.service.url}</url>
<start>${customers.web.service.start}</start>
<end>${customers.web.service.end}</end>
</parameters>
</component>
Times that by seven services, times that by (currently) five services aggerates (no real term for it, it is a super something that uses all seven services) with more to come, and it is a mess.
I ended up with fifty lines or so of configuration that was very hard to read. What I wanted was to be able to do this:
<customers.web.service>
<url>/customers.aspx</url>
<start>12:15</start>
<end>15:41</end>
</customers.web.service>
And be able to reference parts of it from my component configuration like this:
<component id="customers.web.service" type="my.web.service, sample">
<parameters>
<url>${customers.web.service @ url}</url>
<start>${customers.web.service @ start}</start>
<end>${customers.web.service @ end}</end>
</parameters>
</component>
It may not look like a big change, but it focus the eye very clearly about the seperation between various parts of the configuration. And it make it much easier to work with this with code rather than by hand, meaning I could put UI on top of this.
Since I am fairly familiar with Castle, I immediately started hacking and sawing at the configuration parser, to make this kind of syntax possible.
I couldn't make it work cleanly. The configuration parser is a complex beast, and I would be surprise to hear that it is turing complete. It turned out that what I wanted to do would require changing many places, for a dubious benefit. That is when I asked the guys in the Castle list for help, and Hammett and Fabio suggested that I will to use a facility.
A facility in Castle is an implementation of the Open Close Principal, which suggest that:
After taking their advice to heart, I came up with this bit of code, which is short, elegant, and doesn't bother anyone who doesn't want to use it. Here is how the configuration looks like now:
<facilities>
<facility id="nested.configuration.items.facility"
type="Rhino.Commons.NestedConfigurationFacility, Rhino.Commons">
<configuration>
<customers.web.service>
<url>/customers.aspx</url>
<start>12:15</start>
<end>15:41</end>
</customers.web.service>
</configuration>
</facility>
</facilities>
And the component declaration:
<component id="customers.web.service" type="my.web.service, sample">
<parameters>
<url>@{customers.web.service :: url}</url>
<start>@{customers.web.service :: start}</start>
<end>@{customers.web.service :: end}</end>
</parameters>
</component>
Now I am happy.
Comments
Comment preview