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?
Réponse courte: ne pas utiliser le récipient comme un localisateur de services. Google "localisateur de service anti-modèle" –
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? –
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. –