最佳实践:
我已经像一个通用接口通用接口:最佳实践:
public interface IDatabaseElement<T>
{
IList<T> GetAll();
T Get(id);
void Save(T element);
void Delete(int id);
}
如果我有例如仅使用上述方法的两个要素(人员和商店)被认为是最佳实践?
答:制作一个新的接口的每个元素,如:
public interface IPerson : IDatabaseElement<Person> { }
public interface IStore : IDatabaseElement<Store> { }
,然后我的类,如:
public class Person : IPerson { .... }
public class Store : IStore { .... }
和instanciating变量时:
IPerson person = new Person();
IStore store = new Store();
或 乙:直接使用通用接口:
个public class Person : IDatabaseElement<Person> { .... }
public class Store : IDatabaseElement<Store> { .... }
和instainciating当变量:
IDatabaseElement<Person> person = new Person();
IDatabaseElement<Store> store = new Store();
什么被认为是最佳做法?
有一个已知的设计模式,您正在调用IDatabaseElement<T>
;它被称为Repository Pattern。因此,通过重命名IDatabaseElement<T>
开始:
public interface IRepository<TEntity> { ... }
此外,由于你定义IPerson
接口,好像要定义一个接口,为Person
实体,而不是仓库。
将实体隐藏在接口后面是不好的做法,因为实体是数据对象,接口只需要抽象行为。
因此,不要调用接口IPerson
,首先调用它IPersonRepository
。
在另一方面,如果你的Person
类实际上包含数据(如FirstName
,LastName
,Age
等),在这种情况下,你是混合责任。您的实体不应该知道如何从数据库中检索自己(或其他实例!!!)。从数据库中检索数据并保存数据是两种不同的责任,你应该将它们分开(赋予每个责任它自己的类)。如果您违反Single Responsibility Principle,您的系统将很快变得无法维护。
现在,为每个存储库类型(例如IPersonRepository
)制作特定的接口是一个坏主意。有一个通用抽象的主要原因是因为这使得添加额外的行为(如横切关注)更容易,因为这允许您定义一个通用装饰器,例如:AuditTrailingRepositoryDecorator<T>
。但是当你让你的人存储库实现继承自IPersonRepository
时,你不能用泛型装饰器来包装它,只是因为你在IPersonRepository
上定义的所有方法本身都不会被访问。这也使得编写单元测试变得更加容易,因为在你的测试套件中,你只需要创建一个IRepository<T>
的单个通用伪造实现。
如果您对添加横切关注点和轻松测试代码库的能力不感兴趣,可以使用特定(非通用)接口,如IPersonRepository
和IStoreRepository
。
这个问题是偏离主题。 – 2013-05-12 13:03:29
@olf请看看SO的常见问题,这个问题不是关于具体问题。 – Candide 2013-05-12 13:04:52
为什么你的实体首先知道数据库?而且你的方法对一个实体来说是完全荒谬的,他们会适合一个存储库。 – CodesInChaos 2013-05-12 13:06:07