In my last post, I showed you the wonder of the WindsorContainer and creating concrete objects from a config file… but I wasn’t done yet. In fact, if you looked at my example and used your keen sense of observation (I’m suspending my disbelief) you might have noticed a little somethin’ somethin’ in the config file that I didn’t explain:
<component id="factoryB" type="CastleConfigTest.Factory.FactoryB, CastleConfigTest"> </component> <component id="childClassB" type="CastleConfigTest.Interface.IBaseClassB, CastleConfigTest" factoryId="factoryB" factoryCreate="Create"> </component>
And:
<facilities> <facility id="factorysupport" type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.Microkernel" /> </facilities>
What are these??? Could they be the proof of intelligent life we’ve been looking for? Sadly no, since they actually are part of something that sounds a lot more complicated then it is. Say you have this interface:
public interface IBaseClassB { String ClassName(); }
And this class:
public class ChildClassB : IBaseClassB { public String ClassName() { return "ChildClassB"; } }
Which is all pretty straight forward much like that woman’s answer to you asking her out, “God no.”
If you had read this post, you might guess where this is going. Or you might guess that I’m going to re-explain it because you are too lazy to go and read it. One of those is correct.
Once again like my last post I do something simple like this:
var test = new ObjectFactory().Create<IBaseClassB>();
And what I get is a brand new shiny ChildClassB. I can hear the yawns from here SO I’ll change it up a bit. What if I need ChildClassB to come from a Factory? How the hell would I pull that off?
public class FactoryB { public static IBaseClassB Create() { var test = new ChildClassB(); //Do some stuff to test return test; } }
I no longer can just replace IBaseClassB with ChildClassB directly because I need FactoryB to do something for me first. (I cheated by just adding a comment where code might go. Point is, something happens to ChildClassB before the factory returns it.) OH NO! WHAT AM I TO DO? HOW CAN I SOLVE THIS? DOES THE CAPSLOCK ADD SUSPENSE?
Guess what? That’s right, that’s where that config stuff at the top comes in. Here’s the config file in full:
<configuration> <components> <component id="factoryB" type="CastleConfigTest.Factory.FactoryB, CastleConfigTest"> </component> <component id="childClassB" type="CastleConfigTest.Interface.IBaseClassB, CastleConfigTest" factoryId="factoryB" factoryCreate="Create"> </component> </components> <facilities> <facility id="factorysupport" type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.Microkernel" /> </facilities> </configuration>
Ok so I lied, that’s not the full thing I have in my example that you can download, but it is what you need for this part. It’s actually pretty simple too. You just need to declare three things:
The factory class “FactoryB”
<component id="factoryB" type="CastleConfigTest.Factory.FactoryB, CastleConfigTest"> </component>
The interface you want to mask with the factory return (IBaseClassB)
<component id="childClassB" type="CastleConfigTest.Interface.IBaseClassB, CastleConfigTest" //This is the interface to look for factoryId="factoryB" //This is the id from above where you declared the factoryB section factoryCreate="Create"> //This is the method to use </component>
and the Castle part for using factories
<facilities> <facility id="factorysupport" type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.Microkernel" /> </facilities>
And that’s really it. From that, this should work:
[TestMethod] public void Create_ClassB() { //This will call FactoryB.Create to create the ChildClassB for me var test = new ObjectFactory().Create(); Assert.IsTrue(test.ClassName().Equals("ChildClassB")); }
Woo hoo! Now you can run home and impress your Wife/Husband/fiance/partner/thing that lives in your apartment and always seems to pay the rent late but doesn’t have any issue with eating everything in your fridge! Enjoy!