私は最近、RustおよびScalaを学び始めました。そして私を驚かせたのは、C++とJavaで慣れている継承モデルの欠如でした。
Rustでは構造体と特性を使用して単純なものをモデル化できますが、特性と構成を使用してさまざまな種類の問題ドメインをモデル化するより慣用的な方法を見たいと思っています。
たとえば、Observerパターンをモデル化するとします。通常Javaで作成し、
class InterestingThing implements Observable {
private String[] things;
private Object[] observers;
public void register(Observer o) {
... //register
}
public void notifyAll() {
// notify
}
public void deregister(Observer o) {}
// some more stuff
}
class Dude extends Observer<InterestingThing> {
// Observer implementation
}
Rustへの翻訳を求めるのではなく、RustでこのObserverパターンを慣用的にモデル化する方法を確認したいと思います。特性ベースのシステムで問題ドメインを分析およびモデル化するための一般的なガイドライン(すべての名詞はクラスです)は大歓迎です。
Observableメソッドの特性を作成し、特定のInterestingThingの特性を実装できます。
Dudeを監視可能にする場合は、Dudeの特性も実装する必要があります。機能する可能性のある1つのことは、Dudeの構造体メンバーとしてInterestingThingを追加することです。あるいは、後でInterestingThingでインスタンス化する<T: Observable>
アイテムを単に含めることができます。
DudeのObservableメソッドを、含まれているObservableメンバーに転送するだけで十分な場合があります。これには、標準の継承よりもいくらか儀式が関係しますが、デザインの観点からもきれいです。それはあなたがどんなインターフェースが誰にとって重要であるかについてもっと考えることを奨励するでしょう。また、多重継承のような特別なハックで自分を誘惑する必要はありません。あなたの男は興味深いものですか、それとも単に面白いと見なすことができますか?
さらに、Dudeをレコード(単に関連データ)として扱い、<T: Observable>
オブジェクトによってパラメーター化された別のObservableDudeを作成します。
免責事項:私は漠然とRustに精通していますが、継承モデルは非常に一般的です。
-編集-
Rustインターフェースは、多くの関数型言語と同様に継承の概念を採用しています。つまり、インターフェース(トレイト)はオブジェクト(構造体)ではなく継承できます。これは、あなたが示した方法ですが、それは他の理由で役立つかもしれません。
パターンの機構を複数の方法で実装する場合は、InterestingThingがオブザーバーメソッドの厳密なスーパーセットを実装する(したがって、Observableのサブクラスを実装する)インターフェイス階層を作成できます。次に、Observable実装はサブクラスインターフェースの特定の実装を遅延させることができますが、DudeはObservableインターフェースのみを必要とし、「分離」したままです。