インタフェースの継承

ここ暫くは.NET2.0ネタに終始してたし、正直疲れたので、今日は久しぶりにまったりとできるネタ。

次のようなインタフェースがあるとする

public interface FieldAccessible {
    string getFieldA();
    void setFieldA(string fieldA);
    string getFieldB();
    void setFieldB(string fieldB);
    string getFieldC();
    void setFieldC(string fieldC);
}

このインタフェースを使用してJavaでシステムの開発を開始したが、開発が終盤に差しかかろうという時期に、今度は以下のようなインタフェースが必要になったとする。

public interface FieldAccessible2 {
    string getFieldB();
    void setFieldB(string fieldB);
    string getFieldC();
    void setFieldC(string fieldC);
    string getFieldD();
    void setFieldD(string fieldD);
    string getFieldE();
    void setFieldD(string fieldE);
}

FieldAccessibleとFieldAccessible2は似ているが同じでは無い。実は、これらの二つのインタフェースは元々レガシーなシステムから切り出したデータ構造であり、内部ではC言語の共用体で定義していたデータ構造だった経緯がある。なのでフィールド"B"とフィールド"C"は共通だが、互いに共通では無いフィールドも持っている。

この時、互いのインタフェースの関係をどのように設計するのが良いのだろう。

1.インタフェースの継承関係を作る

元々は共有していたデータ構造なのだから、FieldAccessibleとFieldAccessible2は同種のデータである、と考える。従ってインタフェースも継承しているように設計するべきだ。

まずは、共通のフィールドを括り出してルートのインタフェースを設計し

public interface FieldAccessible {
    string getFieldB();
    void setFieldB(string fieldB);
    string getFieldC();
    void setFieldC(string fieldC);
}

その後、差分を継承したインタフェースとして定義する。

public interface FieldAccessible1 extends FieldAccessible {
    string getFieldA();
    void setFieldA(string fieldA);
}
public interface FieldAccessible2 extends FieldAccessible {
    string getFieldD();
    void setFieldD(string fieldD);
    string getFieldE();
    void setFieldD(string fieldE);
}

2. 互いに別なインタフェースとして継承関係は作らない

元々はCの共有体を使用していたとはいえ、似て非なるデータ構造であり"FieldAccessible is FieldAccessible2"の関係は成り立たない。従って、継承関係は作らず、互いに別なインタフェースのまま定義する。

このような場合、私ならば前者(継承関係を作る)を選択する。"is a"の関係が無いと解っていても、だ。実装にはTemplateパータンを用いてFieldAccessibleインタフェースの実装には抽象クラスを用いるだろう。しかし、元々C言語で共用体で使用していただけの2つのデータ構造の間に"is a"の関係を持ち出すのはどうか、という意見もある。"is a"の関係が無い以上、継承関係を作るのは正しくない。これももっともだ。

一体どちらを選択するのが良いだろう。