【问题标题】:interfaces and dependency injection correct use in C#接口和依赖注入在 C# 中的正确使用
【发布时间】:2014-10-30 17:11:39
【问题描述】:

我有一个接口“IUser”和一个实现“IUser”的类“User”。我还有一个用于存储库“IUserRepository”的接口。

我介于这两个选项之间:

public interface IUserRepository
{
    List<User> getAll();
    void addUser(User user);
    void alterUser(User user);
    void deleteUser(string ID);
    bool validateLogin(string session_user, string session_pass);
    User getUserByID(int ID);
    User getUserByNombre(string name);
    User getUserBySessionUser(string session_user);
}

还有这个

public interface IUserRepository
{
    List<IUser> getAll();
    void addUser(IUser user);
    void alterUser(IUser user);
    void deleteUser(string ID);
    bool validateLogin(string session_user, string session_pass);
    IUser getUserByID(int ID);
    IUser getUserByNombre(string name);
    IUser getUserBySessionUser(string session_user);
}

这是我的困惑。我在存储库接口中的方法是否应该返回真实的实现或接口?正如您在我的第一个选项中看到的那样,我正在返回“用户”实例。我应该返回什么来松散耦合代码?

但如果我在用户存储库的实际实现中选择第二个,我将只能访问我在 IUser 接口中声明的方法和属性。

例如,如果我从一个服务中调用 addUser 方法并传递一个 User 类的实例:

   myRepositoryImplementation.addUser(UserInstance);

那么我真正的存储库会喜欢这个

  private readonly IUser user;
  public void addUser(IUser _user)
  {
    this.user=_user;
  }

不错的有效捕获!但是我将只能访问最初在 IUser 接口中声明的方法和属性,而不能访问在我的 User 实例中声明的任何新方法或属性。

如果我调用 getUserByID 方法,我也会收到一个 IUser 实例。

所以继续这个

1)。这些是有效的方法吗?
2)。如果这些是有效的方法,我应该使用哪一种来保留或保持代码解耦?
3)。如果我也选择第二个如果它有效,那么我应该在界面中声明我以后要使用的所有内容吗?我的意思是属性和方法?
3)。有更好的主意吗?

【问题讨论】:

  • 这可能更适合 codereview.stackexchange.com
  • CR.SE 是关于审查工作代码的,而这更像是一个高级设计问题。但是,这可能非常适合程序员。SE
  • 接口的重点是公开属性和方法以供其他代码使用,如果您制作 IUser 接口,它应该包含您需要的所有内容。

标签: c# interface dependency-injection loose-coupling


【解决方案1】:

我肯定会选择第一个选项。为像存储库这样的服务类提供一个接口很有用,但对于像 User 这样的实体类来说,就没那么多用了。

正如您所说,每次添加属性时,您还需要将属性添加到接口,这很繁琐。并且假设您的用户类是一个简单的类,不依赖于其他类,即使没有接口,它也很容易测试。

相关阅读:

http://lostechies.com/jamesgregory/2009/05/09/entity-interface-anti-pattern/

实体上的接口是一种反模式——James Gregory 博客

Should entities implement interfaces?

【讨论】:

    【解决方案2】:

    我认为您的部分困惑是您的 User 类中有方法。通常这些类型的模型类只表示数据,不描述行为。所以,如果你把你的方法移到更合适的地方,你的整个混乱就会消失,因为没有接口的理由。

    换句话说,将方法移出 User 类并让你的 repo 像这样工作:

    List<User> getAll();
    

    【讨论】:

      【解决方案3】:

      1) 是的,两者都有效

      3) 是的,属性和方法

      2) 长一点的故事。简而言之,如果你有 POCO 类并且你 100% 确定你永远不会针对不允许你使用 POCO 的框架编写代码(例如,它坚持类继承自特定于框架的基类),你可以选择第一个选项(类)。

      但它并不总是有效。

      例如,为 Linq2SQL 编码存储库和为实体框架代码编写其他存储库 首先,您不能使用完全相同的一组类。第二种(界面)方法是唯一的选择。我们已在多个企业应用程序中成功使用它,没有出现任何问题。

      忠告——如果你使用接口方法,你肯定需要一个方法来创建一个空实例

      public interface IUserRepository
      {
          List<IUser> getAll();
          ...
          IUser CreateNew();
      }
      

      否则,存储库客户端没有其他方法可以创建具体类型的实例 - 客户端不知道该类型。不过,有些人倾向于将创建方法移到单独的工厂类中。

      【讨论】:

        猜你喜欢
        • 2012-03-15
        • 2017-03-10
        • 2011-07-31
        • 2020-05-11
        • 2023-01-19
        • 2017-06-10
        • 2010-10-06
        相关资源
        最近更新 更多