10

次のコードを検討してください。

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 ステートメントを配置する必要があります。

私には (このテーマは初めてですが)、これは漏れやすい抽象化のように思えます。実装が何かを処理する方法のために、コードにメソッド呼び出しを配置する必要があります。

誰かがこれを理解し、私が正しいか間違っているかを確認するのを手伝ってくれませんか.

ありがとう

4

5 に答える 5

6

はい、特定の実装を念頭に置いて作成したため、ICustomerCreditServiceimplementを許可すると、漏れやすい抽象化になります。さらに、これはそのインターフェイスの消費者に、そのサービスを破棄できることを伝えますが、これは正しくない可能性があります。特に、一般に、リソースはそれを作成した人 (所有権を持っている人) が破棄する必要があるためです。クラスにリソースを注入する場合 (たとえば、コンストラクター注入を使用)、コンシューマーに所有権が与えられているかどうかは明確ではありません。IDisposableICustomerCreditService

したがって、一般に、そのリソースを作成した責任者はそれを破棄する必要があります。

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);       
        }
    }
}
于 2012-09-04T08:46:16.200 に答える
1

最初の実装からやり直して、getInterface-Requestをクラスに追加して、実装がほぼ同じになるようにします。次に、安全に呼び出すことができますDispose(事実上、インターフェイス実装の作成を延期するだけで、ライフサイクルの制御を維持します):( c#-コードは検証されません...)

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);       
    }
  }
}
于 2012-09-04T08:53:48.007 に答える
1

customerCreditService呼び出し元のコードでのライフサイクルを処理する必要があります。MyClass発信者がサービスをまだ必要としているかどうかをどのように知る必要がありますか? 呼び出し元がそのリソースをクリーンアップする責任がある場合、MyClass使い捨てである必要はありません。

// calling method

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

更新:コメントで、OP は Ninject のような IoC の使用について言及しました。コードは次のようになります。

IKernel kernel = ...;

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

kernel.BeginBlock()アクティベーション ブロックを作成します。ブロックが終了したときに、解決されたインスタンスが確実に破棄されるようにします。

于 2012-09-04T08:30:00.360 に答える
1

のライフサイクルがわからないため、ICustomerCreditServiceインスタンス化された場所の Dispose を呼び出す必要があります。MyClassICustomerCreditService

于 2012-09-04T08:30:27.270 に答える
0

はい、そうです。しかし、それは必要な悪です。インターフェースの存在そのものが、漏れのある抽象化ですIDisposable漏れのある抽象化は、単にプログラミングの日常的な事実です。可能な限りそれらを避けてください、しかしあなたができないときは心配しないでください–とにかくそれらは至る所にあります。

于 2012-09-04T08:54:43.583 に答える