Implementing an Abstract Factory by Mark Seemann
Abstract Factory is a tremendously useful pattern when used with Dependency Injection (DI). While I've repeatedly described how it can be used to solve various problems in DI, apparently I've never described how to implement one. As a comment to an older blog post of mine, Thomas Jaskula asks how I'd implement the IOrderShipperFactory.
To stay consistent with the old order shipper scenario, this blog post outlines three alternative ways to implement the IOrderShipperFactory interface.
To make it a bit more challenging, the implementation should create instances of the OrderShipper2 class, which itself has a dependency:
public class OrderShipper2 : IOrderShipper { private readonly IChannel channel; public OrderShipper2(IChannel channel) { if (channel == null) throw new ArgumentNullException("channel"); this.channel = channel; } public void Ship(Order order) { // Ship the order and // raise a domain event over this.channel } }
In order to be able to create an instance of OrderShipper2, any factory implementation must be able to supply an IChannel instance.
Manually Coded Factory #
The first option is to manually wire up the OrderShipper2 instance within the factory:
public class ManualOrderShipperFactory : IOrderShipperFactory { private readonly IChannel channel; public ManualOrderShipperFactory(IChannel channel) { if (channel == null) throw new ArgumentNullException("channel"); this.channel = channel; } public IOrderShipper Create() { return new OrderShipper2(this.channel); } }
This has the advantage that it's easy to understand. It can be unit tested and implemented in the same library that also contains OrderShipper2 itself. This means that any client of that library is supplied with a read-to-use implementation.
The disadvantage of this approach is that if/when the constructor of OrderShipper2 changes, the ManualOrderShipperFactory class must also be corrected. Pragmatically, this may not be a big deal, but one could successfully argue that this violates the Open/Closed Principle.
Container-based Factory #
Another option is to make the implementation a thin Adapter over a DI Container - in this example Castle Windsor:
public class ContainerFactory : IOrderShipperFactory { private IWindsorContainer container; public ContainerFactory(IWindsorContainer container) { if (container == null) throw new ArgumentNullException("container"); this.container = container; } public IOrderShipper Create() { return this.container.Resolve<IOrderShipper>(); } }
But wait! Isn't this an application of the Service Locator anti-pattern? Not if this class is part of the Composition Root.
If this implementation was placed in the same library as OrderShipper2 itself, it would mean that the library would have a hard dependency on the container. In such a case, it would certainly be a Service Locator.
However, when a Composition Root already references a container, it makes sense to place the ContainerFactory class there. This changes its role to the pure infrastructure component it really ought to be. This seems more SOLID, but the disadvantage is that there's no longer a ready-to-use implementation packaged together with the LazyOrderShipper2 class. All new clients must supply their own implementation.
Dynamic Proxy #
The third option is to basically reduce the principle behind the container-based factory to its core. Why bother writing even a thin Adapter if one can be automatically generated.
With Castle Windsor, the Typed Factory Facility makes this possible:
container.AddFacility<TypedFactoryFacility>(); container.Register(Component .For<IOrderShipperFactory>() .AsFactory()); var factory = container.Resolve<IOrderShipperFactory>();
There is no longer any code which implements IOrderShipperFactory. Instead, a class conceptually similar to the ContainerFactory class above is dynamically generated and emitted at runtime.
While the code never materializes, conceptually, such a dynamically emitted implementation is still part of the Composition Root.
This approach has the advantage that it's very DRY, but the disadvantages are similar to the container-based implementation above: there's no longer a ready-to-use implementation. There's also the additional disadvantage that out of the three alternative here outlined, the proxy-based implementation is the most difficult to understand.
Comments
But i have a question. What if object, created by factory, implements IDisposable? Where we should call Dispose()?
Sorry for my English...
Often, when I open this blog from the google search results page, javascript function "highlightWord" hangs my Firefox. Probably too big cycle on DOM.
You can read more about this in chapter 6 in my book.
Regarding the bug report: thanks - I've noticed it too, but didn't know what to do about it...
You have cleand up my doubts with this sentence "But wait! Isn’t this an application of the Service Locator anti-pattern? Not if this class is part of the Composition Root." I was not just confortable about if it's well done or not.
I use also Dynamic Proxy factory because it's a great feature.
Thomas
I thought about this "life time" problem. And I've got an idea.
What if we let a concrete factory to implement the IDisposable interface?
In factory.Create method we will push every resolved service into the HashSet.
In factory.Dispose method we will call container.Release method for each object in HashSet.
Then we register our factory with a short life time, like Transitional.
So the container will release services, created by factory, as soon as possible.
What do you think about it?
About bug in javascript ...
Now the DOM visitor method "highlightWord" called for each word. It is very slow. And empty words, which passed into visitor, caused the creation of many empty SPAN elements. It is much slower.
I allowed myself to rewrite your functions... Just replace it with the following code.
var googleSearchHighlight = function () {
if (!document.createElement) return;
ref = document.referrer;
if (ref.indexOf('?') == -1 || ref.indexOf('/') != -1) {
if (document.location.href.indexOf('PermaLink') != -1) {
if (ref.indexOf('SearchView.aspx') == -1) return;
}
else {
//Added by Scott Hanselman
ref = document.location.href;
if (ref.indexOf('?') == -1) return;
}
}
//get all words
var allWords = [];
qs = ref.substr(ref.indexOf('?') + 1);
qsa = qs.split('&');
for (i = 0; i < qsa.length; i++) {
qsip = qsa[i].split('=');
if (qsip.length == 1) continue;
if (qsip[0] == 'q' || qsip[0] == 'p') { // q= for Google, p= for Yahoo
words = decodeURIComponent(qsip[1].replace(/\+/g, ' ')).split(/\s+/);
for (w = 0; w < words.length; w++) {
var word = words[w];
if (word.length)
allWords.push(word);
}
}
}
//pass words into DOM visitor
if(allWords.length)
highlightWord(document.getElementsByTagName("body")[0], allWords);
}
var highlightWord = function (node, allWords) {
// Iterate into this nodes childNodes
if (node.hasChildNodes) {
var hi_cn;
for (hi_cn = 0; hi_cn < node.childNodes.length; hi_cn++) {
highlightWord(node.childNodes[hi_cn], allWords);
}
}
// And do this node itself
if (node.nodeType == 3) { // text node
//do words iteration
for (var w = 0; w < allWords.length; w++) {
var word = allWords[w];
if (!word.length)
continue;
tempNodeVal = node.nodeValue.toLowerCase();
tempWordVal = word.toLowerCase();
if (tempNodeVal.indexOf(tempWordVal) != -1) {
pn = node.parentNode;
if (pn && pn.className != "searchword") {
// word has not already been highlighted!
nv = node.nodeValue;
ni = tempNodeVal.indexOf(tempWordVal);
// Create a load of replacement nodes
before = document.createTextNode(nv.substr(0, ni));
docWordVal = nv.substr(ni, word.length);
after = document.createTextNode(nv.substr(ni + word.length));
hiwordtext = document.createTextNode(docWordVal);
hiword = document.createElement("span");
hiword.className = "searchword";
hiword.appendChild(hiwordtext);
pn.insertBefore(before, node);
pn.insertBefore(hiword, node);
pn.insertBefore(after, node);
pn.removeChild(node);
}
}
}
}
}
I upload .js file here http://rghost.ru/37057487
Granted, if the constructor to OrderShipper2 changes, you MUST modify the abstract factory. However, isn't modifying the constructor of OrderShipper2 itself a violation of the OCP? If you are adding new dependencies, you are probably making a significant change.
At that point, you would just create a new implementation of IOrderShipper.
(Thank you very much for your assistance with the javascript - I didn't even know which particular script was causing all that trouble. Unfortunately, the script itself is compiled into the dasBlog engine which hosts this blog, so I can't change it. However, I think I managed to switch it off... Yet another reason to find myself a new blog platform...)
Btw, another thing I think about is the abstract factory's responsibility. If factory consumer can create service with the factory.Create method, maybe we should let it to destroy object with the factory.Destroy method too? Piece of the life time management moves from one place to another. Factory consumer takes responsibility for the life time (defines new scope). For example we have ControllerFactory in ASP.NET MVC. It has the Release method for this.
In other words, why not to add the Release method into the abstract factory?
However, what if we have a desktop application or a long-running batch job? How do we define an implicit scope then? One option might me to employ a timeout, but I'll have to think more about this... Not a bad idea, though :)
But for a single long-lived thread we have to invent something.
It seems that there is no silver bullet in the management of a lifetime. At least without using Resolve-Release pattern in several places instead of one ...
Can you write another book on this subject? :)
A Task<T>, on the other, provides us with the ability to attach a continuation, so that seems to me to be an appropriate candidate...
Or you could register the container with itself, enabling it to auto-wire itself.
None of these options are particularly nice, which is why I instead tend to prefer one of the other options described above.
Julien, thank you for your question. Using a Dynamic Proxy is an implementation detail. The consumer (in this case LazyOrderShipper2) depends only on IOrderShipperFactory.
Does using a Dynamic Proxy make it harder to swap containers? Yes, it does, because I'm only aware of one .NET DI Container that has this capability (although it's a couple of years ago since I last surveyed the .NET DI Container landscape). Therefore, if you start out with Castle Windsor, and then later on decide to exchange it for another DI Container, you would have to supply a manually coded implementation of IOrderShipperFactory. You could choose to implement either a Manually Coded Factory, or a Container-based Factory, as described in this article. It's rather trivial to do, so I would hardly call it blocking issue.
The more you rely on specific features of a particular DI Container, the more work you'll have to perform to migrate. This is why I always recommend that you design your classes following normal, good design practices first, without any regard to how you'd use them with any particular DI Container. Only when you've designed your API should you figure out how to compose it with a DI Container (if at all).
Personally, I don't find container verification particularly valuable, but then again, I mostly use Pure DI anyway.