In un'altro post di qualche giorno fa mi è stato chiesto di approfondire alcuni concetti.

Partiamo dal primo: IServiceContainer.

Come forse avrete capito sono leggermente ossessionato dal problema delle dipendenze e siccome in moltissimi casi liberarsene costa veramente poco faccio sempre il possibile per farlo. Nello specifico in questo periodo stiamo facendo uso massiccio di Castle Windsor come motore di Inversion of Control ma la mia ossessione mi dice che non è bello dipendere da Castle perchè domani mattina potremmo volerci mettere Sping.NET o Unity... quindi?!?!

Molto semplicemente astraimo l'uso che facciamo di Castle mascherandolo. In questo momento ci stiamo avvalendo solo delle funzionalità di IoC quindi abbiamo una semplice interfaccia:

public interface IServiceContainer
{
    T GetService<T>() where T : IService; 
    IService GetService( Type serviceType ); 
    void Release( Object instance );
}

l'applicazione a sua volta a runtime, sempre via IoC (ma con una implementazione custom non con Castle naturalmente), ottiene un'istanza di una classe concreta "CastleServiceContainer" che implementa l'interfaccia in oggetto.

public sealed class ServiceContainer : IServiceContainer
{
    private static IServiceContainer _instance = new ServiceContainer();
    public static IServiceContainer GetContainer()
    {
        return _instance;
    }

    private ServiceContainer()
    {
        Type t = Type.GetType(Properties.Settings.Default.ServiceProviderType, true);
        this.provider = Activator.CreateInstance(t) as IServiceContainer;
    }

    private IServiceContainer provider;
    public T GetService<T>() where T : IService
    {
        return this.provider.GetService<T>();
    }

    public IService GetService( Type serviceType )
    {
        return this.provider.GetService( serviceType );
    }

    public void Release( Object instance )
    {
        this.provider.Release( instance );
    }
}

Infine abbiamo il "provider" vero e proprio, in questo caso quello che sfrutta (ed è l'unico che lo sa) Castle Windsor.

public class CastleServiceProvider : IServiceContainer
{
    IWindsorContainer container = null;

    public CastleServiceProvider()
    {
        this.container = new WindsorContainer(
            new XmlInterpreter(
                new ConfigResource( "applicationSettings/ServiceProvider.Configuration" )
            )
        );
    }

    public T GetService<T>() where T : IService
    {
        return this.container.GetService<T>();
    }

    public IService GetService( Type serviceType )
    {
        Object obj = this.container.GetService( serviceType );
        return ( IService )obj;
    } 

    public void Release( Object instance )
    {
        this.container.Release( instance );
    }
}

In questo modo l'applicazione sfrutta tutto quello che le serve senza sapere in realtà chi le sta fornendo questi servizi.

Quanto costa tutto ciò? forse, e ripeto forse, un pomeriggio di lavoro, se ci mettiamo che dal codice che ho postato ho rimosso la gestione delle Exception e il motore di tracing/logging; ma lo ritengo un pomeriggio decisamente ben speso! l'unico vero problema: farlo capire al cliente... ma questa è un'altra storia ;-)

.m

Technorati Tags: ,