PHPの例
例1: mpyw/co
実践的なプロジェクト…といえるかどうか微妙ですが(笑),自作しているライブラリでたまに継承は使用したりするので,その中でもコードが短くて読みやすい一例を紹介させていただきます.言語はPHPで,「限りなくJavaScriptのasync/awaitに近い非同期HTTPリクエスト処理が書ける」というのをモットーにしているライブラリです.
このライブラリは内部で有名なC言語製のlibcurlおよびそれのPHPバインディングを使っています.PHP7.0.7以降ではうまいことリクエストを集中させすぎないように抑制するオプションが設けられているのですが,7.0.6以前では存在していないため手動制御しています.双方に出来るだけラクに対応できるように,抽象クラスと継承を利用しています.
実際のファイルは以下になります.
自動スケジューラではadd()
されたリクエストを全部即座にlibcurlに丸投げしていますが,手動スケジューラでは「一定数だけlibcurlに投げて(addImmediate()
),上限を超えたぶんはPHP側で保持しておく(addReserved()
)」というように振り分けており,さらに何かリクエストが1つ終わるたびに1個ずつPHPで保持しておいたもの取り出してlibcurlに投げる(interruptConsume()
)ことをやっています.このように,内部的な動作が微妙に違います.
但しクラスが独自に持っているものはprivateに過ぎず,継承を抽象クラスから強制されたものはすべてprotectedかpublicになっており,それを呼び出す側からはどちらも同じAbstractSchedulerとして扱える点がミソです.Pool.phpでは3行だけでこの場合分けが済んでおり,中身がどちらになっているかを全く意識する必要がありません.
もし2つのクラスを両方とも一から作る場合,同じようなメソッドをまるまるコピペする場所が生まれてしまって,変更するときに面倒になったり,コードの美しさが損なわれたりします.これを最小限に抑える手段の1つとして,継承は有効です.ただし最近では継承よりもインタフェースや**ミックスイン(トレイト)**といった手法のほうが好まれることが増えてきており,使い場所を見極める必要はあります.
例2: guzzle/psr7 と slimphp/Slim
PSR-7という仕様で決められたメッセージインタフェースの実装例ですが,こちらでは継承を全く使わずにトレイトを活用しています.
一方こちらはトレイトを使わずに継承でやってます.
このように,同じインタフェースを実装する目的でも,2通りのやり方があります.慣れてくるとどっちを使ったほうがいいか何となくわかるようになります[要出典]
TypeScriptの例
例3: angular/angular
AngularJSのバージョン2.x系のソースが参考になると思います.
こちらはPHPの例で紹介したSlimのやり方と非常によく似ていますね.