我有不同类型的文档:DocumentCitizen,DocumentOther,DocumentResolution等。每种文档类型都有相应的存储库:DocumentCitizenRepository,DocumentOtherRepository,DocumentResolutionRepository。所有存储库都有一个名为Documents的属性和一个名为SaveDocument的方法。以下是DocumentCitizenRepository的内容作为示例:
public class DocumentCitizenRepository{
EFDbContext context= new EFDbContext();//EFDbContext inherits DbContext
public IQueryable<DocumentCitizen> Documents{get{context.DocmentsFromCitizens}}
public void SaveDocument(DocumentCitizen doc)
{//omitted for brevity}
}
其他存储库的内容类似。因此,我希望所有存储库都扩展一个名为Repository的抽象类。我还为所有名为Document的文档类型定义了一个抽象类,其中包含空内容:
public abstract class Document{}
public abstract class Repository{
public abstract IQueryable<Document>{get;}
public abstract void SaveDocument(Document doc)
}
但是我收到有关无效或丢失覆盖的警告,因为编译器需要属性和方法的签名是相同的。要看到差异:
基本抽象类中的方法:
public abstract void SaveDocument(Document doc)
和继承类中的那个:
public abstract void SaveDocument(DocumentCitizen doc)
所以我完全不知道是否有可能做我想做的事情。你有什么想法吗?
答案 0 :(得分:2)
最有可能的是,您甚至可以更进一步,创建一个完全通用的基础仓库:
public interface IRepository<T>
{
IQueryable<T> GetQueryable();
void Save(T item);
}
public abstract class BaseRepository<T> : IRepository<T>
{
public IQueryable<T> GetQueryable() { ... }
public void Save(T item) { ... }
}
您仍然可以使用特定的存储库接口来创建特定于实体的方法:
public interface IDocumentCitizenRepository : IRepository<DocumentCitizen>
{
// this interface has no extra methods, just the plain ol' CRUD
}
public interface IDocumentResolutionRepository : IRepository<DocumentResolution>
{
// this one can do additional stuff
void DoSomethingSpecial(DocumentResolution doc);
}
抽象基类用于重用通用功能:
// this class will inherit everything from the base abstact class
public class DocumentCitizenRepository
: BaseRepository<DocumentCitizen>, IDocumentCitizenRepository
{ }
// this class will inherit common methods from the base abstact class,
// and you will need to implement the rest manually
public class DocumentResolutionRepository
: BaseRepository<DocumentResolution>, IDocumentResolutionRepository
{
public void DoSomethingSpecial(DocumentResolution doc)
{
// you still need to code some specific stuff every once in a while
}
}
这通常与依赖注入一起使用,因此您只需在业务层中使用接口而无需关心实际实现:
var repo = container.Resolve<IDocumentCitizenRepository>();
repo.Save(doc);
最后一部分(依赖注入)应该在组合根中完成,这意味着直接在整个代码中使用容器(“服务定位器”模式)并不是抽象这些依赖关系的理想方式。尝试组织您的类以通过构造函数接收存储库接口,这将允许您在进行单元测试时轻松模拟每个repo。
答案 1 :(得分:1)
我通常倾向于做以下事情:
public interface IRepository<T> where T: class
{
bool Delete(T entity);
bool Save(T entity);
}
然后您可以使用repo ...
private IRepository<DocumentCitizen> _docCitizen;
在你的方法中,你可以像所有的回购......
DocumentCitizen doc = new DocumentCitizen{....}
_docCitizen.Save(doc);
您可以将其作为构造函数参数传递...
public DocumentService(
IRepository<DocumentCitizen> docCitizen)
{
_docCitizen = docCitizen;
}
答案 2 :(得分:1)
在我看来,让DocumentCitizenRepository
从单个抽象Save
类继承其DocumentRepository
方法是没有意义的,因为DocumentCitizenRepository
无法保存任意文档。通过继承该方法,您违反了Liskov substitution principle。
对于GetDocuments
方法,问题不同。 DocumentCitizenRepository.GetDocuments ()
返回特定类型的文档,如果DocumentCitizen
继承自Document
,则可以将其视为文档,因此DocumentCitizenRepository.GetDocuments ()
是某些文档的有效实现{ {1}}方法。
方法:
DocumentRepository.GetDocuments ()