interfaceは要るのか
クロージャを一々渡してられないようなものもある。GetEnumerator, Count, インデクサ、Dispose辺りはいちいち自分で「Disposeのメソッドはこれです」なんて指定していたら発狂してしまうかもしれない。そういうものにはinterfaceは必要だろう。あとフレームワークはコレクションのAddを欲しがる。
IEnumerable<T> GetEnumerator() ICollection<T> Count{ get; } IList<T> this[int index]{ get; } IDictionary<T> TryGetValue(key, out value) 要るか? IDisposable Dispose() ICanAdd<T> Add(T item) IComparable<T> CompareTo(T item)
こんなもんだろうか。最初からC# 3.0の言語機能があるなら、俺だったらこれ以外のinterfaceは作らなかった。いや、どうだろう。IEquatable
Addなんかはなしにして配列をとるコンストラクタとかIEnumerable
interfaceにした方がいい条件というのは
デフォルト動作を指定する確率が高いので指定させる必要が無い && 頻繁に出てくるので指定させるとうるさくなる && オブジェクトの基本的な属性なので他の属性と重なったオブジェクトが作れないと困る
かなり絞られてくると思う。自作する必要なんてまずないだろう。ユーザーが動作を指定できるようにするにはクロージャの方がよほどいいし、動作を指定する必要がほとんどなくてもオブジェクトの基本的な属性でないなら継承でいい。
それを見越していたのか、Windows.Formsはびっくりするほどinterfaceがない。代わりに関数型の変数が腐るほどある。インターフェースを実装したクラスを作らせるなんてのは本当に最悪のコードを苦痛を伴って書かせるだけの行為だということを良く分かっている。自分でinterfaceを実装しなさいなんていうコードは今後二度と書いちゃいけない。
interfaceを使ってもいいケースは、デフォルト実装を使うのが当たり前すぎてデフォルト実装を指定する部分がわずらわしく感じるが、オブジェクトの基本的な属性なので継承できないことがある場合、単一目的のオブジェクトに出来ないことがある場合だけだ。つまりそんな場合はまずないということだ。まずないというか無いようにしなきゃいけない。interfaceはデフォルト実装を指定するためにばかり使われるので、ダラダラと委譲コードを書き連ねるハメになる。間にクラスが挟まるので見通しが悪くなり、めんどくさいし何にもいいことはない。
IList
そうじゃなくて、たとえばその処理に末尾のAddとRemoveが必要なら、
void Process<T>(Action<T> push, Action pop) List<T> list = new List<T>(); Process(list.Add, () => list.RemoveAt(list.Count - 1))
こうすればいい。めんどくさいなら、自分で
void Process<T>(List<T> list) { Process(list.Add, () => list.RemoveAt(list.Count - 1); }
こういうのを作ればいい。これさえあれば
LinkedList<T> linkedList = new LinkedList<T>(); Process(linkedList.AddLast, linkedList.RemoveLast)
LinkedListにもちゃんと適用できる。
でもなんかもうちょっとあるような気もするなあ。interfaceにした方がいい場合が。