インターフェイスをどのように進化させ、バージョン管理しますか?


22

インターフェイスがあるとしましょうIFoo

public interface IFoo {
    void Bar(string s);
    int Quux(object o);
}

APIのバージョン2では、Glargこのインターフェイスにメソッドを追加する必要があります。既存のAPIユーザーを破壊せず、後方互換性を維持せずに、どのように行いますか?これは主に.NETを対象としていますが、他のフレームワークと言語にも適用できます。


問題なく追加できます。問題は、すでにそこにあるものを変更/削除するときに発生します。
リグ

1
@Rig:少なくともC#では、インターフェイスにメソッドを追加し、そのインターフェイスを実装するクラスに追加しないと、コンパイルエラーが発生します。
悪意

まあ、それは本当です。メソッドのシグネチャを変更したり、シグネチャを削除したりするのに比べて、混乱を最小限に抑えることができるユーザークラスのシナリオからもっと考えていました。したがって、インターフェイスに追加する必要がある場合は、何らかの作業につながる可能性があると思います。
リグ

回答:


9

APIのバージョン2では、Glargこのインターフェイスにメソッドを追加する必要があります。

どうして?

APIで使用するために定義されたインターフェイスには、2つのまったく異なる役割があります。

  1. 依存関係の反転-このようなインターフェースはAPIによって消費されます。クライアントコードでプラグインなどを作成できます。
  2. 抽象化-このようなインターフェースはAPIによって返され、返されたオブジェクトの実装の詳細を隠します。

今のために与えられたバージョンのAPIの、同じインターフェイスは両方として作用することができます。それでも、将来のバージョンでは、これを切り離すことができます。

  1. 使用するインターフェイスからより多くの情報を抽出する必要があります。パフォーマンスを強化するため、または柔軟性などを追加するため。おそらく古いインターフェースから派生した新しいインターフェースを定義し、それを使用する別のメソッドを構築します。私の知る限り、ほとんどの.NET言語ではメソッドのオーバーロードが許可されているため、これはあまり煩雑にならずに実行できます。
  2. 「もっと返す」、つまりAPIから「より豊富な」オブジェクトを抽象化する必要があります。ここでは、2つの選択肢があります。

    • クライアントコードには、インターフェイスの独自の実装者がいないと合理的に推測できます。この仮定の下では、既存のインターフェースに拡張機能を追加しても安全です。
    • 可能であれば前のインターフェイスから派生した新しいインターフェイスを定義します。そのような派生が不可能な場合は、新しいインターフェイスのインスタンスを照会するか、構成を使用する別のメソッドを作成します。

      interface MyNewInterface extends MyOldInterface { 
           FancyNewInterface getFancyShit();
      }
      

15

DirectXは、インターフェイスにバージョン番号を追加しました。あなたの場合、解決策は次のようになります

public interface IFoo2 : IFoo
{
    void Glarg();
}

APIは引き続きIFooを参照し、IFoo2機能が必要なメソッドなどでのみIFoo2を参照します。

API実装は、IFoo2でメソッドのセマンティクスが異なる場合、IFooパラメーターオブジェクトがIFoo2を実際に実装するかどうかを既存の(=バージョン1)メソッドでチェックする必要があります。


3

APIに新しいメソッドを追加するには、既存のAPIに副作用が生じないようにする必要があります。最も重要なことは、新しいAPIが存在しないかのように古いAPIを使い続ける人は、その影響を受けないことです。古いAPIを使用しても、新しいAPIに予期しない副作用が生じることはありません。

APIの既存のメソッドのいずれかが新しいものに置き換えられる場合は、すぐに削除しないでください。それらを非推奨としてマークし、代わりに何を使用すべきかについて説明してください。これにより、コードのユーザーに、警告なしにコードを壊すのではなく、将来のバージョンでサポートされなくなる可能性があることを警告します。

新しいAPIと古いAPIに互換性がなく、望ましくない副作用がなければ共存できない場合は、それらを分離し、新しいAPIを採用する場合は古いAPIを完全に廃止する必要があることを文書化します。常に両方を使用しようとする人がいて、それが機能しない場合はイライラするため、これはあまり望ましくありません。

.NETについて具体的に尋ねたので、次の例にリンクされている.NETの非推奨に関するこの記事を読むことをお勧めしますObsoleteAttribute

using System;

public sealed class App {
   static void Main() {      
      // The line below causes the compiler to issue a warning:
      // 'App.SomeDeprecatedMethod()' is obsolete: 'Do not call this method.'
      SomeDeprecatedMethod();
   }

   // The method below is marked with the ObsoleteAttribute. 
   // Any code that attempts to call this method will get a warning.
   [Obsolete("Do not call this method.")]
   private static void SomeDeprecatedMethod() { }
}

2

パブリックインターフェイスの変更には破損が伴います。一般的な戦略は、これらをメジャーバージョンとフリーズ期間後にのみ行うことです(気まぐれでは発生しません)。新しいインターフェイスに追加を追加する場合は、クライアントを中断せずに逃げることができます(そして、実装は同じクラスで両方を提供できます)。それは理想的ではありません。それをやり続けると混乱が生じます。

ただし、他の種類の変更(メソッドの削除、署名の変更)では、スタックします。


2
将来のメソッド名のプリフィックスをプリエンプティブに予約し、すべてのユーザーにそのネームスペースを使用するべきではないことを警告できますが、それでも洗練されていないAPIになります。一般に、親は絶対に正しいです。メソッド削除(および追加)すると、既存のユーザー破損するため、賢明な計画を立てること以外にできることはありません。
キリアンフォス

1

インターフェイスはコントラクトであるため、バージョン管理を行うべきではありません。サッカー選手が新しい契約を取得するとどうなりますか?古いものはまだ有効ですか?いいえ。インターフェイスを変更すると、契約が変更され、以前の契約(インターフェイス)は無効になります。

IFoo2戦略を使用することもできますが、次のような場合に最終的には面倒になります。

  • IFoo2
  • IFoo3
  • IFoo4

うん

APIは異なります。使用するコードのライブラリを提供します。来月、更新されたライブラリを提供します。別のポスターが言ったように、私がすでに使用しているものを壊さないで、新しい機能/メソッドを追加してください。

何かをバージョン管理する場合は、インターフェイスの代わりに抽象クラスを使用します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.