c# – 最佳实践:通用接口

我做了一个通用的界面,如:

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 { .... }

当实例化变量时:

IPerson person = new Person();
IStore store = new Store();

要么
B:直接使用通用接口,如:

public class Person : IDatabaseElement<Person> { .... }
public class Store : IDatabaseElement<Store> { .... }

当实现变量时:

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)创建一个特定的接口是个坏主意.具有通用抽象的主要原因是因为这使得添加额外行为(例如横切关注点)变得更加容易,因为这允许您定义单个通用装饰器,例如:AuditTrailingRepositoryDe​​corator< T>.但是当你让你的人员存储库实现继承自IPersonRepository时,你不能再用通用的装饰器包装它,因为你在IPersonRepository上定义的所有方法都不再可访问了.这也使得编写单元测试变得更加容易,因为在测试套件中,您只需要创建一个IRepository< T>的通用虚假实现.

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

转载注明原文:c# – 最佳实践:通用接口 - 代码日志