它是一个抽象的漏水,如果实现的接口调用Dispose(Is it a leaky abstracti

2019-06-27 19:00发布

考虑以下代码:

public class MyClass()
{
  public MyClass()
  {    
  }

  public DoSomething()
  {
    using (var service = new CustomerCreditServiceClient())
    {
       var creditLimit = service.GetCreditLimit(
         customer.Firstname, customer.Surname, customer.DateOfBirth);       
    }
  }
}

我们现在希望把它重构为松散耦合它。 我们结束了这一点:

public class MyClass()
{
  private readonly ICustomerCreditService service;

  public MyClass(ICustomerCreditService service)
  {
     this.service= service;
  }

  public DoSomething()
  {
     var creditLimit = service.GetCreditLimit(
       customer.Firstname, customer.Surname, customer.DateOfBirth);       
  }
}

看起来没问题吧? 现在,任何实现可以使用的界面和一切都很好。

如果我现在说的实现是一个WCF类和using语句做重构之前是有原因的。 即/关闭WCF连接。

所以,现在我们的接口必须实现Dispose方法调用或者我们使用一个工厂接口得到执行,并把using语句解决这一问题。

对我来说(虽然新的主题)这似乎是一个漏水的抽象。 我们不得不把方法调用在我们的代码只是为了执行正在处理的东西的方式着想。

有人能帮助我理解这一点,并确认我是否正确或错误。

谢谢

Answer 1:

是的,这是一个漏水的抽象,当你让ICustomerCreditService实现IDisposable ,因为你现在已经写ICustomerCreditService用一记具体实施。 更进一步,这传达到该接口,它可以部署该服务,这可能是不正确的,特别是因为在一般情况下,资源应由谁创造它的人(谁拥有所有权)可配置的消费者。 当你注入的资源放到一个类(使用构造器注入为例),如果消费者被赋予所有权,目前尚不清楚。

所以一般一个负责创建资源应该处理它。

然而,在你的情况,你可以简单地防止这种甚至通过实施非一次性执行发生ICustomerCreditServiceClient简单地创建和部署同样的方法调用中的WCF客户端。 这使得一切都容易得多:

public class WcfCustomerCreditServiceClient
    : ICustomerCreditServiceClient
{
    public CreditLimit GetCreditLimit(Customer customer)
    {
        using (var service = new CustomerCreditServiceClient())
        {
            return service.GetCreditLimit(customer.Firstname,
                customer.Surname, customer.DateOfBirth);       
        }
    }
}


Answer 2:

你应该调用的Dispose ICustomerCreditService它已被实例化为MyClass现在已经没有生命周期的理念ICustomerCreditService



Answer 3:

与第一实施重新开始,我会尝试一个getInterface请求添加到类,以便实现可能留下或多或少相同。 然后,它可以安全地调用Dispose (实际上它只是推迟接口实现的创建,但在其生命周期的控制保持):(C#-code未验证...)

public class MyClass()
{
  public delegate ICustomerCreditService InterfaceGetter;
  private InterfceGetter getInterface;
  public MyClass(InterfaceGetter iget)
  {
    getInterface = iget;
  }
  public DoSomething()
  {
    using (var customerCreditService = getInterface())
    {
       var creditLimit = customerCreditService.GetCreditLimit(customer.Firstname, customer.Surname, customer.DateOfBirth);       
    }
  }
}


Answer 4:

你应该处理的生命周期customerCreditService调用代码。 应该如何MyClass知道,如果服务仍然由主叫用户需要的? 如果来电者是负责清理它的资源,然后MyClass不必是一次性的。

// calling method

using (var service = new CustomerCreditServiceClient()) {
    var myClass = new MyClass(service);
    myClass.DoSomething();
}

更新:在评论OP提到使用一个IoC像Ninject的。 然后,该代码看起来是这样的:

IKernel kernel = ...;

using (var block = kernel.BeginBlock())
{
    var service = block.Get<ICustomerCreditService>();
    var myClass = new MyClass(service);
    myClass.DoSomething();
}

所述kernel.BeginBlock()创建一个激活块。 它确保当块结束的解决实例配置。



Answer 5:

是的。 但是,这是一个必要之恶。 在本身的存在 IDisposable接口是一个漏水的抽象。 漏水的抽象只是编程的一个日常的事实。 避免在可能的地方,但是当你无法也不必担心 - 他们是无处不在的反正。



文章来源: Is it a leaky abstraction if implementation of interface calls Dispose