1

我使用接口的主要原因是使单元测试变得容易。但我觉得我不理解如何 100% 使用接口。

这是我正在尝试做的简化版本:

public interface IPlan
{
    List<Plan> GetPlans(IPlan plan);
    List<Plan> GetAllPlans();
    List<string> DoSomethingElse();
}

public class Plan : IPlan
{
    List<Plan> GetPlans(IPlan plan)
    {
        // 
    List<Plan> planList = plan.GetAllPlans();

    //
    // Do stuff with planList...
    //
}

为了设置单元测试,我需要能够模拟 Plan 类并从 GetAllPlans 返回一组计划,所以我看到我应该在这里使用接口,以便我可以正确地模拟它。我也明白(或至少我认为)我应该将一个 IPlan 对象传递给 GetPlans,然后我应该使用该 IPlan 对象来调用 GetAllPlans ......但是这个设置似乎有些不对劲。

我设置不正确吗?我传递一个与它所在的类相同类型的 IPlan 似乎很奇怪(我将传递一个作为计划的 IPlan)。对此有何建议?

4

4 回答 4

2

我认为,您的困惑源于您的计划课程的偏离性质。您有一个可能封装了一些计划数据的类,但它也提供了处理自身列表的方法。

没有看到更多代码,很难确定,但您可能应该从移动GetPlansGetAllPlans进入另一个处理计划列表的类开始。然后将他们的签名更改为

List<IPlan> GetPlans();
List<IPlan> GetAllPlans();

甚至可能使该类是通用T : IPlan的,因此受到以下签名的约束:

List<T> GetPlans();
List<T> GetAllPlans();
于 2013-11-12T14:32:32.563 回答
0

您正在正确实施它。接口中定义的每个方法都必须在您的具体类中实现。

我不明白你的问题是......

“我传递一个与它所在的类相同类型的 IPlan 似乎很奇怪(我将传递一个作为计划的 IPlan)。”

你能澄清一下吗?

如果您的意思是 List GetPlans(),那么这样的事情是完全可以预期的。您正计划返回一系列计划。

该接口定义了一些框架方法,每个实现的类都应该实现。这是一个“合同”的基础,以保证类将实现此接口。这也意味着你可以做一些事情,比如你知道你有一个 IPlugin 接口的插件,你可以使用说反射来加载实现了这个接口的程序集并开始调用类中的方法。

也许您需要一个名为 Plan 的实体类,然后将实现 IPlan 的当前 Plan 类重命名为 PlanOperations 或其他东西。似乎这个类将完成这项工作,而您的计划只是一个可能有设置器的实体/对象

于 2013-11-12T14:25:34.617 回答
0

接口是一种契约,旨在(可能)应用于许多对象。它基本上告诉您的应用程序任何实现接口的对象都将实现您在接口中指定的方法。

它是为松散耦合而设计的。而不是您的方法接受计划对象,例如:

public bool DoSomething(Plan plan)
{
//....
}

您可以使用 IPlan:

public bool DoSomething(IPlan plan)
{
//....
}

这意味着在运行时,您可以将任何内容传递给该方法,只要它实现了 IPlan。

这也意味着,对于单元测试,您可以创建 IPlan 的虚拟实现(例如,如果 IPlan 正常与数据库通信,您不希望它发生在您的测试中)并通过它 - 这样您就只是在测试方法中的代码,而不是该方法及其在 Plan 中调用的任何内容。

于 2013-11-12T14:31:31.963 回答
0

好吧,从技术上讲,您的实现是正确的,但是接口在其方法中使用该接口的具体实现似乎很奇怪。看起来IPlan是在试图“做太多”。

相反,我会有这样的东西:

public interface IPlanRepository
{
    IEnumerable<IPlan> GetPlans(IPlan plan);
    IEnumerable<IPlan> GetAllPlans();
    IEnumerable<string> DoSomethingElse();
}

public class PlanRepository : IPlanRepository
{
    IEnumerable<IPlan> GetPlans(IPlan plan)
    {
        // fill a List with Plans
    }
    IEnumerable<IPlan> planList = GetAllPlans();
    {
        // fill a List with Plans
    }
    //
    // Do stuff with planList...
    //
}

public interface IPlan
{
   // properties and methods relating to a Plan (NOT how to "get" a Plan)
}

public class Plan : IPlan
{
    // implementation of properties and methods
}

请注意,我还将List返回类型更改为更通用的IEnumerable接口。这使您可以灵活地在实现中返回任何返回IEnumerable<Plan>诸如 List<Plan>,Plan[]IQueryable<Plan>如果您正在使用 ORM 的东西。

于 2013-11-12T14:40:53.170 回答