Castle.Windsor is a powerful IoC framework. Since being cajoled into using it by a co-worker, I've come to really like it's features. Today I'm making a brain dump of something cool the TypedFactoryFacility can do. For those that don't know, this facility provides, "... automatically generated abstract factories..."
The Problem
I was creating a service host which exposed a few endpoints. These in turn called the business specific functionality. The service class already had four or five business specific methods on it. That's a lot of dependencies to put in a constructor.
public class DrinkServiceWithoutFactory : IDrinkService
{
private readonly Fridge fridge;
private readonly Machine machine;
public DrinkServiceWithoutFactory(Fridge fridge, Machine machine)
{
this.fridge = fridge;
this.machine = machine;
}
public IList<Can> GetCans()
{
return fridge.Dispense();
}
public IList<Bottle> GetBottles()
{
return machine.Dispense();
}
}
public class Fridge : IDispenser<Can>
{
public IList<Can> Dispense()
{
Console.WriteLine("Creating 1 Can...");
return new List<Can>
{
default(Can)
};
}
}
public class Machine : IDispenser<Bottle>
{
public IList<Bottle> Dispense()
{
Console.WriteLine("Creating 2 bottles...");
return new List<Bottle>
{
default(Bottle),
default(Bottle)
};
}
}
The Solution
An abstract factory was used to create the business-specific objects on demand, reducing the number of dependencies being injected into the constructor. the TypedFactoryFacility provides a handy means of creating delegate- or interface- based abstract factories automagically. What's not illustrated on the Castle documents site is that it can also create factories with generic methods.
The interface-based factory docs page explains how to create and use a factory interface. It doesn't really mention that the create method can also contain a generic. Below is an example of one that does.
public interface IDispenserFactory
{
T Create<T>()
where T : IDispenser;
void Release(IDispenser iDispenser);
}
This depends on two other definitions:
public interface IDispenser
{
}
public interface IDispenser<T> : IDispenser
where T : class
{
IList<T> Dispense();
}
Now that we have the factory setup, we can register the components: public class Program
{
static void Main()
{
try
{
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
Component.For<Demo>(),
Component.For<Machine>(),
Component.For<Fridge>(),
Component.For<IDispenserFactory>().AsFactory(),
Component.For<IDrinkService>().ImplementedBy<DrinkService>()
);
var demo = container.Resolve<Demo>();
demo.Run();
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
finally
{
Console.ReadKey();
}
}
}
public class Demo
{
private readonly IDrinkService service;
public Demo(IDrinkService service)
{
this.service = service;
}
public void Run()
{
var bottles = service.GetBottles();
Console.WriteLine("Bottles created: {0}", bottles.Count);
var cans = service.GetCans();
Console.WriteLine("Cans created: {0}", cans.Count);
}
}
We can then change the service implementation to use the abstract factory:
public class DrinkService : IDrinkService
{
private readonly IDispenserFactory factory;
public DrinkService(IDispenserFactory factory)
{
this.factory = factory;
}
public IList<Can> GetCans()
{
var fridge = factory.Create<Fridge>();
return fridge.Dispense();
}
public IList<Bottle> GetBottles()
{
var machine = factory.Create<Machine>();
return machine.Dispense();
}
}
The results (quick and dirty):
![]() |
| The results... |
Summary
This was just a quick brain dump to illustrate that the TypedFactoryFacility can do generics as well.

No comments:
Post a Comment