2010-04-14 16 views
0

J'ai trois assemblys: "Framework.DataAccess", "Framework.DataAccess.NHibernateProvider" et "Company.DataAccess". A l'intérieur de l'ensemble « Framework.DataAccess », j'ai mon usine (avec la mauvaise mise en œuvre de la découverte):Comment puis-je configurer une Usine avec les fournisseurs possibles?

public class DaoFactory 
{ 
    private static readonly object locker = new object(); 
    private static IWindsorContainer _daoContainer; 

    protected static IWindsorContainer DaoContainer 
    { 
     get 
     { 
      if (_daoContainer == null) 
      { 
       lock (locker) 
       { 
        if (_daoContainer != null) 
         return _daoContainer; 

        _daoContainer = new WindsorContainer(new XmlInterpreter()); 

        // THIS IS WRONG! THIS ASSEMBLY CANNOT KNOW ABOUT SPECIALIZATIONS! 
        _daoContainer.Register(
         AllTypes.FromAssemblyNamed("Company.DataAccess") 
          .BasedOn(typeof(IReadDao<>)).WithService.FromInterface(), 
         AllTypes.FromAssemblyNamed("Framework.DataAccess.NHibernateProvider") 
          .BasedOn(typeof(IReadDao<>)).WithService.Base());       
       } 
      } 

      return _daoContainer; 
     } 
    } 

    public static T Create<T>() 
     where T : IDao 
    { 
     return DaoContainer.Resolve<T>(); 
    } 
} 

Cet ensemble définit également l'interface de base pour l'accès aux données IReadDao:

public interface IReadDao<T> 
{ 
    IEnumerable<T> GetAll(); 
} 

Je veux pour garder cet ensemble générique et sans références. C'est mon assemblage d'accès aux données de base.

Ensuite, j'ai l'assembly du fournisseur NHibernate, qui implémente l'IReadDao ci-dessus en utilisant l'approche de NHibernate. Cet assembly fait référence à l'assembly "Framework.DataAccess".

public class NHibernateDao<T> : IReadDao<T> 
{ 
    public NHibernateDao() 
    { 
    } 

    public virtual IEnumerable<T> GetAll() 
    { 
     throw new NotImplementedException(); 
    } 
} 

Enfin, j'ai l'assemblée « Company.DataAccess », qui peut remplacer l'implémentation par défaut du fournisseur NHibernate et références les deux ensembles précédemment vus.

public interface IProductDao : IReadDao<Product> 
{ 
    Product GetByName(string name); 
} 

public class ProductDao : NHibernateDao<Product>, IProductDao 
{ 
    public override IEnumerable<Product> GetAll() 
    { 
     throw new NotImplementedException("new one!"); 
    } 

    public Product GetByName(string name) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Je veux être capable d'écrire ...

IRead<Product> dao = DaoFactory.Create<IRead<Product>>(); 

... puis obtenir la mise en œuvre ProductDao. Mais je ne peux pas tenir à l'intérieur de mon accès aux données de base toute référence à des assemblages spécifiques! Mon idée initiale était de lire cela à partir d'un fichier de configuration XML. Donc, ma question est: Comment puis-je configurer cette usine en externe pour utiliser un fournisseur spécifique comme implémentation par défaut et comme implémentation client?

+1

Réponse courte: ne pas utiliser le récipient comme un localisateur de services. Google "localisateur de service anti-modèle" –

+0

Une suggestion? J'ai quelques implémentations d'accès aux données, par ex. CsvProvider, NHibernateProvider et XmlProvider. En fonction de l'entité de domaine, j'aurai une implémentation par défaut différente. Comment puis-je séparer/configurer le conteneur/l'usine? –

+0

Encore une chose: l'exigence m'assure qu'une entité n'aura qu'un seul magasin de données, ce qui signifie que chaque entité n'aura qu'un seul type d'implémentation d'accès aux données. –

Répondre

0

Vous l'avez.

J'utilise IWindsorInstaller pour mettre en œuvre les paquets:

public class TestDaoInstaller : IWindsorInstaller 
{ 
    public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
     container.Register(
      AllTypes.FromAssemblyNamed("Company.DataAccess") 
       .BasedOn(typeof(IReadDao<>)).WithService.FromInterface(), 
      AllTypes.FromAssemblyNamed("Framework.DataAccess.NHibernate") 
       .BasedOn(typeof(IReadDao<>)).WithService.Base()); 
    } 
} 

Et Framework.DataAccess, mon conteneur est maintenant:

protected static IWindsorContainer DaoContainer 
{ 
    get 
    { 
     if (_daoContainer == null) 
     { 
      lock (locker) 
      { 
       if (_daoContainer != null) 
        return _daoContainer; 

       _daoContainer = new WindsorContainer(new XmlInterpreter()); 
       IWindsorInstaller[] daoInstallers = _daoContainer.ResolveAll<IWindsorInstaller>(); 
       foreach (IWindsorInstaller daoInstaller in daoInstallers) 
        _daoContainer.Install(daoInstaller); 

      } 
     } 

     return _daoContainer; 
    } 
}