Molti conoscono windsor castle il (più?) famoso IoC container. Pochi però sanno che oltre a poter essere usato come semplice contenitore Castle dispone di alcune utili "facility" che permettono di estenderne il funzionamento.
Di seguito vorrei parlare delle Factory.
Per default un oggetto registrato all'interno del file di configurazione di Castle viene costruito usando il costruttore e iniettando gli eventuali parametri necessari.
A volte però capita di dover costruire un oggetto avvalendosi di una classe factory che si occupa della costruzione e setup di un oggetto.
Castle supporta nativamente questo modo di costruzione degli oggetti basta configurarlo nel modo corretto.
Supponete di voler configurare Castle per farvi tornare l'instanza della sessione di NHibernate, come saprete la sessione non può essere costruita tramite il new ma deve essere costruita tramite una classe SessionFactory di solito incapsulata in un NHibernateHelper:
public static class NHibernateHelper
{
private static readonly ISessionFactory sessionFactory;
static NHibernateHelper()
{
Configuration cfg = new Configuration();
cfg.Configure();
sessionFactory = cfg.BuildSessionFactory();
}
public static ISession GetNewSession()
{
return sessionFactory.OpenSession();
}
// ...
}
La classe NHibernateHelper ha un metodo statico GetNewSession che ritorna un'instanza di una classe ISession.
Voglio usare questa classe tramite IoC per costruire delle ISession da iniettare (ad esempio) in un Repository:
public class UserRepository : IUserRepository
{
public UserRepository(ISession session)
{
//...
}
}
L'unica cosa da fare è istruire Castle tramite il file di configurazione (o tramite codice se preferite):
<castle>
<facilities>
<facility id="factorysupport" type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.Microkernel" />
</facilities>
<components>
<component id="session"
type="NHibernate.ISession, NHibernate"
factoryId="sessionFactory"
factoryCreate="GetNewSession" />
<component id="sessionFactory"
type="NHibernateHelper, CodicePlastico.Samples" />
<component id="userRepository"
service="CodicePlastico.Samples.Repositories.IUserRepository, CodicePlastico.Samples"
type="CodicePlastico.Samples.UserRepository, CodicePlastico.Samples" />
</components>
</castle>
Il primo blocco (facilities) aggiunge il supporto necessario alle factory specificando quale classe si occuperà di gestire le factory all'interno di castle.
Poi vengono registrati i componenti.
Il primo (session) è l'oggetto che verrà creato tramite una factory, specifico il tipo (Isession) e l'id del componente che farà da factory per ISession (sessionFactory) e il metodo che dovrà utilizzare per la costruzione degli oggetti ISession (GetNewSession).
Naturalmente anche la classe factory deve essere registrata (componente sessionFactory) e questo avviene tramite la consueta sintassi, come pure la classe UserRepository.
Cosa succede quando richiedo al container un oggetto di tipo IUserRepository?
Il container vede che il tipo concreto è UserRepository e che il suo costruttore riceve in ingresso un'istanza di ISession che a sua volta deve essere costruita tramite il metodo GetNewSession della classe NHibernateHelper.
Questa tecnica è utile in quei contesti in cui l'oggetto non può essere creato direttamente ma si deve utilizzare un'altra classe che si occupa della instanziazione.