多重継承、Mix-in、テンプレート(*´д`*)ハァハァハァアハァ
Struts の Action を拡張して機能を追加していく上で、悩ましい問題が発生しました。
一口に機能の追加といっても、今回のプロジェクトでは二つのカテゴリについて機能の追加を行なうことになりました。
- FWの機能的な面での機能追加
- 業務の共通的な処理の機能追加
普通にクラスの継承を行なって、これらの機能を追加できれば良いのですが、そうはうまくいきませんでした。
その理由として、FW機能と業務共通処理とはそれぞれ独立した機能であり、それぞれ独立した継承ツリーとなることがあります。
/** 機能拡張元のクラス */ public class Action {...} /** FWの機能拡張 */ public class AbstractAction extends Action {...} public class AbstractViewAction extends AbstractAction {...} public class AbstractUpdateAction extends AbstractAction {...} /** 業務の共通機能 */ public class AbstractBizAction extends Action {...}
実際に業務処理を実装する場合、イメージ的には上記のような親クラスを用意して、AbstractViewAction と AbstractBizAction を継承したクラスを作成したいのですが、Java の場合多重継承が許されていないため実現でません。
かといって、業務の共通機能をFWの機能拡張に含めてしまうのも、設計として誤っているとおもいます。
もし、Java に Mix-in があれば、AbstractViewAction を継承した業務実装クラスに、AbstractBizAction の機能を Mix-in することで、やりたいことは実現できるのですが・・・
あるいは、Java のジェネリクスが C++ のテンプレートのように、コンパイル時に型の解決を行なうのであれば、以下ような書き方で二つの機能を一つのコンクリートクラスに継承できるのですが・・・
/** 業務の共通機能 */ public class AbstractBizActionextends T {...} /** 業務実装クラス */ // 業務共通クラスの親クラスとして、FWの機能拡張クラスの AbstractViewAction を指定 public class ConcreteBizAction extends AbstractBizAction {...}
でも、残念ながら Java のジェネリクスはコンパイル時に型の解決を行なわないため、extends T のような指定は行なえません。コンパイル時は所詮、Object 型として認識されていたりするので。*1
同様の理由により、Java では new T() というのできません。*2
ってわけで、Java で二つの機能をひとまとまりに扱いたい場合は、コンポジットなどによりうまく扱う必要があります。ブリッジパターンとか。Mix-in か、extends T をできるようにして( ゜д゜)ホスィ…