Contexte / Question
J'ai travaillé sur de nombreux .NET les projets qui ont été nécessaires pour maintenir les données et ont généralement fini à l'aide d'un Dépôt de modèle. Personne ne sait d'une bonne stratégie pour sortir autant de code réutilisable sans sacrifier la base de code de l'évolutivité?
La Stratégie D'Héritage
Car une grande partie du code de Référentiel est la plaque de la chaudière et doit être répété j'ai l'habitude de créer une classe de base pour couvrir les notions de base comme la gestion des exceptions, l'enregistrement et le soutien à la transaction, ainsi que quelques méthodes CRUD de base:
public abstract class BaseRepository<T> where T : IEntity
{
protected void ExecuteQuery(Action query)
{
//Do Transaction Support / Error Handling / Logging
query();
}
//CRUD Methods:
public virtual T GetByID(int id){}
public virtual IEnumerable<T> GetAll(int id){}
public virtual void Add (T Entity){}
public virtual void Update(T Entity){}
public virtual void Delete(T Entity){}
}
Si cela fonctionne bien quand j'ai un simple domaine, je me permet de créer rapidement un SÈCHE classe de dépôt pour chaque entité. Cependant, cela commence à se décomposer lorsque le domaine devient de plus en plus complexe. Disons une nouvelle entité est introduit qui ne permet pas de mises à jour. Je peux briser les classes de base et déplacer la méthode de mise à Jour dans une classe différente:
public abstract class BaseRepositorySimple<T> where T : IEntity
{
protected void ExecuteQuery(Action query);
public virtual T GetByID(int id){}
public virtual IEnumerable<T> GetAll(int id){}
public virtual void Add (T entity){}
public void Delete(T entity){}
}
public abstract class BaseRepositoryWithUpdate<T> :
BaseRepositorySimple<T> where T : IEntity
{
public virtual void Update(T entity){}
}
Cette solution ne permet pas à l'échelle. Disons que j'ai plusieurs personnes qui ont une méthode commune: public virtual void Archive(T entity){}
mais certaines Entités qui peuvent être Archivés peuvent également être mis à Jour, tandis que d'autres ne le peuvent pas. Donc, mon Héritage solution se décompose, je dois créer deux nouvelles classes de base pour faire face à ce scénario.
Compoisition Stratégie
J'ai exploré la Composition du motif, mais ce qui semble laisser beaucoup de chaudière plaque de code:
public class MyEntityRepository : IGetByID<MyEntity>, IArchive<MyEntity>
{
private Archiver<MyEntity> _archiveWrapper;
private GetByIDRetriever<MyEntity> _getByIDWrapper;
public MyEntityRepository()
{
//initialize wrappers (or pull them in
//using Constructor Injection and DI)
}
public MyEntity GetByID(int id)
{
return _getByIDWrapper(id).GetByID(id);
}
public void Archive(MyEntity entity)
{
_archiveWrapper.Archive(entity)'
}
}
Le MyEntityRepository est maintenant chargé de code réutilisable. Est-il un outil / motif que je peux utiliser pour générer automatiquement ce?
Si je pouvais tourner la MyEntityRepository en quelque chose comme ceci, je pense que ce serait loin d'être idéal:
[Implement(Interface=typeof(IGetByID<MyEntity>),
Using = GetByIDRetriever<MyEntity>)]
[Implement(Interface=typeof(IArchive<MyEntity>),
Using = Archiver<MyEntity>)
public class MyEntityRepository
{
public MyEntityRepository()
{
//initialize wrappers (or pull them in
//using Constructor Injection and DI)
}
}
La Programmation Orientée Aspects
J'ai regardé dans l'aide d'une AOP cadre pour ce faire, spécifiquement PostSharp et leur Composition Aspect, qui ressemble, il devrait faire l'affaire, mais dans le but d'utiliser un Référentiel je vais appeler la Poste.Cast<>(), ce qui ajoute une très étrange odeur du code. Quelqu'un sait si il ya une meilleure façon d'utiliser l'AOP pour aider à se débarrasser du compositeur code réutilisable?
Personnalisé Générateur De Code
Si tout le reste échoue, je suppose que je pourrais travailler à la création d'une Coutume Générateur de Code de Visual Studio plug in qui pourrait produire de la chaudière de la plaque de code dans un partiel fichier de code. Il y a déjà un outil qui permettrait de faire cela?
[Implement(Interface=typeof(IGetByID<MyEntity>),
Using = GetByIDRetriever<MyEntity>)]
[Implement(Interface=typeof(IArchive<MyEntity>),
Using = Archiver<MyEntity>)
public partial class MyEntityRepository
{
public MyEntityRepository()
{
//initialize wrappers (or pull them in
//using Constructor Injection and DI)
}
}
//Generated Class file
public partial class MyEntityRepository : IGetByID<MyEntity>, IArchive<MyEntity>
{
private Archiver<MyEntity> _archiveWrapper;
private GetByIDRetriever<MyEntity> _getByIDWrapper;
public MyEntity GetByID(int id)
{
return _getByIDWrapper(id).GetByID(id);
}
public void Archive(MyEntity entity)
{
_archiveWrapper.Archive(entity)'
}
}
Les Méthodes D'Extension
Oublié d'ajouter cela, lorsque j'ai d'abord écrit à la question (désolé). J'ai aussi essayé d'expérimenter avec des méthodes d'extension:
public static class GetByIDExtenions
{
public T GetByID<T>(this IGetByID<T> repository, int id){ }
}
Cependant, cela a deux problèmes, d'une part, je dois rappeler à l'espace de noms de l'extension des méthodes de la classe et de l'ajouter partout et b) les méthodes d'extension ne peuvent pas satisfaire à l'interface de dépendances:
public interface IMyEntityRepository : IGetByID<MyEntity>{}
public class MyEntityRepository : IMyEntityRepository{}
Mise à jour: Serait - Modèles T4 être une solution possible?