首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >程序员说“针对接口而不是对象进行编码”是什么意思?

程序员说“针对接口而不是对象进行编码”是什么意思?
EN

Stack Overflow用户
提问于 2010-12-16 08:39:47
回答 7查看 19.8K关注 0票数 80

我已经开始了漫长而艰巨的学习和将测试驱动程序应用到我的工作流程中的探索。我的印象是,测试驱动开发非常符合IoC原则。

在浏览了SO中的一些TDD标记问题后,我读到了针对接口而不是对象进行编程的好主意。

您能否提供简单的代码示例,说明这是什么,以及如何将其应用于实际用例?简单的例子是我(和其他想要学习的人)掌握概念的关键。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2010-12-16 08:44:05

考虑一下:

class MyClass
{
    //Implementation
    public void Foo() {}
}

class SomethingYouWantToTest
{
    public bool MyMethod(MyClass c)
    {
        //Code you want to test
        c.Foo();
    }
}

因为MyMethod只接受一个MyClass,所以如果你想用一个模拟对象替换MyClass来进行单元测试,你不能。更好的方法是使用一个接口:

interface IMyClass
{
    void Foo();
}

class MyClass : IMyClass
{
    //Implementation
    public void Foo() {}
}

class SomethingYouWantToTest
{
    public bool MyMethod(IMyClass c)
    {
        //Code you want to test
        c.Foo();
    }
}

现在可以测试MyMethod了,因为它只使用一个接口,而不是特定的具体实现。然后,您可以实现该接口来创建用于测试目的的任何类型的mock或fake。甚至还有像Rhino Mocks的Rhino.Mocks.MockRepository.StrictMock<T>()这样的库,它可以接受任何接口并为您动态构建一个模拟对象。

票数 84
EN

Stack Overflow用户

发布于 2010-12-16 08:59:54

这都是亲密关系的问题。如果您为实现(已实现对象)编写代码,那么您与“其他”代码处于非常密切的关系中,因为它是它的消费者。这意味着你必须知道如何构造它(即,它有什么依赖关系,可能作为构造函数参数,可能作为setter),何时处理它,如果没有它,你可能做不了什么。

实现的对象前面的接口允许您做一些事情-

  1. 例如,您可以/应该利用工厂来构造对象的实例。IOC容器为你做得很好,或者你也可以自己做。由于构建职责不在您的职责范围内,您的代码可以假定它正在获得它所需要的东西。在工厂墙的另一边,您可以构造真实的实例,也可以模拟类的实例。在生产中,你当然会使用real,但为了测试,你可能想创建存根或动态模拟的实例来测试各种系统状态,而不必运行系统。
  2. 你不必知道对象在哪里。这在分布式系统中很有用,在分布式系统中,您想要与之对话的对象可能位于您的进程甚至系统的本地,也可能不在本地。如果您曾经编写过Java RMI或旧的skool EJB,您就会知道“与接口对话”的例程,该例程隐藏了一个代理,该代理执行客户端不必关心的远程联网和编组职责。WCF具有类似的“与接口对话”的哲学,并让系统确定如何与目标object/service.

通信

** UPDATE ** IOC Container (Factory)示例请求。有许多适用于几乎所有平台的,但它们的核心是这样工作的:

  1. 在应用程序启动例程中初始化容器。有些框架通过配置文件或代码,或者两者兼而有之。
  2. 您可以“注册”您希望容器为您创建的实现,作为它们实现的接口的工厂(例如:为服务接口注册MyServiceImpl )。在此注册过程中,您通常可以提供一些行为策略,例如,如果每次都创建一个新实例,或者在容器为您创建对象时使用单个(吨)实例
  3. ,它会在创建过程中将所有依赖项注入到这些对象中(即,如果您的对象依赖于另一个接口,则会依次提供该接口的实现,依此类推)。

它可能看起来像这样:

IocContainer container = new IocContainer();

//Register my impl for the Service Interface, with a Singleton policy
container.RegisterType(Service, ServiceImpl, LifecyclePolicy.SINGLETON);

//Use the container as a factory
Service myService = container.Resolve<Service>();

//Blissfully unaware of the implementation, call the service method.
myService.DoGoodWork();
票数 19
EN

Stack Overflow用户

发布于 2010-12-16 08:47:21

在对接口进行编程时,您将编写使用接口实例而不是具体类型的代码。例如,您可以使用以下模式,其中包含构造函数注入。构造函数注入和控制反转的其他部分并不是针对接口进行编程所必需的,但是,由于您是从测试驱动程序和IoC的角度出发的,所以我已经用这种方式将其连接起来,为您提供一些您希望熟悉的上下文。

public class PersonService
{
    private readonly IPersonRepository repository;

    public PersonService(IPersonRepository repository)
    {
        this.repository = repository;
    }

    public IList<Person> PeopleOverEighteen
    {
        get
        {
            return (from e in repository.Entities where e.Age > 18 select e).ToList();
        }
    }
}

仓库对象是传入的,并且是一个接口类型。传入接口的好处是能够在不改变使用的情况下“交换出”具体的实现。

例如,假设在运行时,IoC容器将注入一个连接到数据库的存储库。在测试期间,您可以传入模拟或存根存储库来测试您的PeopleOverEighteen方法。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4456424

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档