私は失われており、神の指導を必要としています。最初abstact hierarcyの具体的なインスタンスに対する契約を強制する
まず物事:
class IProduct
{
public:
virtual void DoThings();
}
enum ProductType
{
...
}
class IProducer
{
public:
virtual IProduct* Produce(ProductType type);
}
class IConsumer
{
public:
virtual void Consume(IProduct* product);
}
その無地のシンプルで:喜んでこれらの新たに生み出されたのiProduct提供する抽象工場、インタフェースを起動します抽象消費者、あなたには、いくつかの素敵な-きちんとインターフェースを持っていると仮定します。 しかし、ここでトリッキーな部分が来る。 は、2つ(またはそれ以上)の平行具体的なグループがあると仮定します。
class ConcreteProducerA : public IProducer { ... }
class ConcreteConsumerA : public IConsumer { ... }
class ConcreteProductA : public IProduct { ... }
class ConcreteProducerB : public IProducer { ... }
class ConcreteConsumerB : public IConsumer { ... }
class ConcreteProductB : public IProduct { ... }
そして、それらのコンクリートはreeealy異なるものです。スペースシャトルの部品(パーツ工場とシャトル組立ライン)と野菜の袋(農場やイドクと一緒に、野菜を消費する人は誰ですか?)のように。しかし、彼らは一般的にそれを持っている:DoThings()。それがあなたが好きなものであれば、PackAndSend()、Serialize()、Dispose()のように振る舞います。何も具体的ではありませんが、階層を基盤とする合法です。 しかし、それらはまだ一般性よりも多くの違いがあります。だから、コンクールコンサルタントは違った使い方をしているのです。つまり、実際には、具体的なタイプと思われていることを絶対に確かめなければなりません。
ここに問題があります:私はその階層のユーザーに、現在の仮想優先で、IPoductをConcreteProductに強制的にダウンキャストしようとしています。そしてそれは私を苦労させている。私は何かが欠けていると感じる:階層の大きな欠陥、パターン知識の欠如、何か。 私は、ConcreteConsumerBは常にConcreteProductBを受信することを確認できますが、それでもダウンキャストです。そしてあなたはいつも(void *)の周りを回り、あなたが来ると思っている時にそれを投げるように強制するフレームワークを使っていますか?私はすでに考えられてきた
ソリューション:
- トンネルすべてconctrete interfeces IProductに。しかし、その製品のgonaは、Eat()、BeEaten()、Launch()、Destroy()、そして何が他のものかを知っている誰でも知ることができない制御不能なブロブに変わります。だから、この解決法は私に落ち着かせることよりも優れているようです。
- DoThings()は、IProductから別のハンドラに切り離されている可能性があります。このハンドラはすべてのConcret(Visitor-like)を受け入れることができます。そうすれば、IP製品は取り除かれ、別個の具体的なグループが作られます。しかし、それらの具体的なグループに共通の機能を実装しているSemiConcreteレイヤーがあればどうでしょうか?ラベリング、モーフィング、マッサージなど。また、別の具体的なグループを追加する必要があるときは、その訪問者を変更することが強制されます。これは、カップリングを増やします。
(ab)テンプレートを使用します。それは現時点では賢明なようです。
template < typename _IProduct > class IConcreteProducer : public IProducer { public: virtual _IProduct* Produce(_IProduct::Type type) = 0; virtual _IProduct::Type DeduceType(ProductType type) = 0; virtual IProduct* Produce(ProductType type) { return IConcreteProducer<typename _IProduct>::Produce(DeduceType(type)); } } template < typename _IProduct > class IConcreteConsumer : public IConsumer { public: virtual void Consume(_IProduct* product) = 0; virtual void Consume(IProduct* product) { IConcreteConsumer<typename _IProduct>::Consume((_IProduct*)product); } }
このように私はそのダウンキャストをコントロールしていますが、それは残念です。
とにかく、この問題はおなじみですか?誰かがそれを見たか、あるいは英雄的にそれを自分で解決しましたか? C + +のソリューションは素晴らしいだろうが、私は統計的に型付けされた言語で十分だと思う。
もしも* "reeealy different things" *は継承階層であり、工場は本当に仕事のために本当に適切なツールですか? – Flexo
これは明らかに間違っています: 'IConcreteConsumer' –
Nawaz
@awoodlandよくダウンキャストが必要ですが、コードの再利用(セマンティクスは別として)のために、いくつか共通の基盤から派生するのに十分です。派生から離れてgracefuly再利用する別の方法はありますか(まだOOP形式を維持しています)? – Dark