[Effective C#] 項目19 継承よりもインターフェイスの定義および実装を行うこと

今日の Effective C# は、「項目19 継承よりもインターフェイスの定義および実装を行うこと」です。

これ重要です!

オブジェクト指向を学び出したころは、継承による差分プログラミングを夢見ていました。でもまあ、これは失敗に終わりました。(もちろん、継承による差分プログラミングが有効だったときもありますが)

個人的にインターフェイスを使うべき最大の理由が、Mock Object の問題です。例えば、NMock はインターフェイスの Mock しか作れません。ですので、継承ではなく、極力インターフェイスを使うようになりました。(クラスの Mock を作れるのもありますが、その場合 virtual メソッドに限定されるので、やっぱり使えなかったりします)

そしたらなんか別のメリットが出てきてびっくりしました。

使い古された言い方ですが、継承関係は「~である」ことを表し、インターフェイスは「~のように振る舞う」ことを表しています。これらの言い回しが長いこと使われてきたのは、双方の構造の違いを実にうまく表現しているためです。親クラスはオブジェクトがどのようなものであるかを表現し、インターフェイスはそれがどのような挙動をするかを表現するのです。

結論として、インターフェイスを定義して、それを実装する抽象クラスを用意するのがいい感じです。

public interface IFoo
{
    void Show()
}
 
public abstract FooBase : IFoo
{
    public void Show()
    {
        Debug.WriteLine(string.Format("This is a {0}.", GetItemType();
    }
 
    protected abstract string GetItemType();
}

こんな感じですね。ほとんどの場合は抽象クラスを継承すれば済みますし、それで足りない場合はインターフェイスを直接実装すればいいわけです。

また、単一継承しかできない C# において、インターフェイスは複数実装できるので、それもインターフェイスのメリットとなります。

例えば、抽象クラスしか用意されていない場合、CollectionBase を継承しつつ、その抽象クラスを継承したいと思ってもできませんが、CollectionBase を継承しつつ、インターフェイスを実装する、ならできます。なので、極力インターフェイスを用意すべきです。

ちなみに、多重継承を行いたい気分になったら、そのクラスの役目が複数あるということのようでして、クラス分割をを考えた方がよいようです。

引数と返り値に関しても、インターフェイスを使うことを検討する必要があると述べられています。

public void PrintCollection(IEnumerable collection)
{
    foreach (object o in collection)
        Console.WriteLine("コレクション内の要素: {0}", o.ToString());
}
 
public void PrintCollection(CollectionBase collection)
{
    foreach (object o in collection)
        Console.WriteLine("コレクション内の要素: {0}", o.ToString());
}

しかし、2つ目のメソッドはひとつ目に比べて圧倒的に再利用性が低いものです。2つ目のメソッドは配列や ArrayList、DataTable、Hashtable、ImageList、あるいはそのほか多くのコレクションクラスを引数にとることができません。メソッドの引数の型をインターフェイスとすることにより、汎用性を上げることができるため、メソッドの再利用性を高めることができます。

最後の説明は構造体のボックス化・ボックス化解除の問題の回避でした。インターフェイス経由で引数を渡したり、アクセスしている限り、構造体はボックス化もボックス化解除もされません。

余談ですが、インターフェイスは強い約束事です。それらがはっきりとするので、やり取りはインターフェイスを使うってのは非常に分かりやすいです。

また、[オブジェクト指向設計原則]依存関係逆転の原則(DIP)とかにあるように、インターフェイスを使うことで、依存関係の逆転を行うことができます。

まじ大事っす!

コメントを追加

Filtered HTML

  • ウェブページアドレスとメールアドレスは、自動的にハイパーリンクに変換されます。
  • 使用できるHTMLタグ: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <blockquote> <img>
  • 次のタグを使用してソースコード構文をハイライトすることができます。: <code>, <blockcode>, <c>, <cpp>, <drupal5>, <drupal6>, <java>, <javascript>, <php>, <python>, <ruby> The supported tag styles are: <foo>, [foo].
  • 行と段落は自動的に折り返されます。

Plain text

  • HTMLタグは利用できません。
  • ウェブページアドレスとメールアドレスは、自動的にハイパーリンクに変換されます。
  • 行と段落は自動的に折り返されます。
CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
イメージ CAPTCHA
Enter the characters shown in the image.
エラー | まさくらのブログ

エラー

サイトに予期せぬエラーが起こりました。しばらくたってから再度お試しください。