2013-05-12 223 views
4

我已经像一个通用接口通用接口:最佳实践:

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(); 

什么被认为是最佳做法?

+0

这个问题是偏离主题。 – 2013-05-12 13:03:29

+0

@olf请看看SO的常见问题,这个问题不是关于具体问题。 – Candide 2013-05-12 13:04:52

+1

为什么你的实体首先知道数据库?而且你的方法对一个实体来说是完全荒谬的,他们会适合一个存储库。 – CodesInChaos 2013-05-12 13:06:07

回答

7

有一个已知的设计模式,您正在调用IDatabaseElement<T>;它被称为Repository Pattern。因此,通过重命名IDatabaseElement<T>开始:

public interface IRepository<TEntity> { ... } 

此外,由于你定义IPerson接口,好像要定义一个接口,为Person实体,而不是仓库。

将实体隐藏在接口后面是不好的做法,因为实体是数据对象,接口只需要抽象行为。

因此,不要调用接口IPerson,首先调用它IPersonRepository

在另一方面,如果你的Person类实际上包含数据(如FirstNameLastNameAge等),在这种情况下,你是混合责任。您的实体不应该知道如何从数据库中检索自己(或其他实例!!!)。从数据库中检索数据并保存数据是两种不同的责任,你应该将它们分开(赋予每个责任它自己的类)。如果您违反Single Responsibility Principle,您的系统将很快变得无法维护。

现在,为每个存储库类型(例如IPersonRepository)制作特定的接口是一个坏主意。有一个通用抽象的主要原因是因为这使得添加额外的行为(如横切关注)更容易,因为这允许您定义一个通用装饰器,例如:AuditTrailingRepositoryDecorator<T>。但是当你让你的人存储库实现继承自IPersonRepository时,你不能用泛型装饰器来包装它,只是因为你在IPersonRepository上定义的所有方法本身都不会被访问。这也使得编写单元测试变得更加容易,因为在你的测试套件中,你只需要创建一个IRepository<T>的单个通用伪造实现。

如果您对添加横切关注点和轻松测试代码库的能力不感兴趣,可以使用特定(非通用)接口,如IPersonRepositoryIStoreRepository