私の会社では、並行して動作し、共通のメッセージングシステムを使用して互いにメッセージを送信するさまざまな「サービス」を用意しています。すべてのメッセージオブジェクトは、メッセージング用に定義した共通の汎用オブジェクトから派生しています。サービスがメッセージを受信すると、最初に必要なことは、オブジェクトを派生型にダウンキャストして、必要なデータを抽出できるようにすることです。
ベースオブジェクトポインターを派生オブジェクトポインターにダウンキャストする必要はないこと、およびこれを行う必要があることは、多くの場合、設計が悪いことを示しています。ほとんどの場合、この感情に同意します。また、ダウンキャストを必要としない、汎用メッセージオブジェクトのさまざまなデザインを想像できます。しかし、この状況を別の方法で処理する大きな理由はないと思います。
だから私の全体的な質問は:ダウンキャストは常に悪いことですか?ダウンキャストが必要または許容される状況はありますか?
ポインターをダウンキャストすることと、特定のオブジェクトに汎用ペイロードを作成することは、2つの異なるものです。
一般的なメッセージングシステムAPIには、必要なオブジェクトを正確に返すための一連の関数が必要です。これにより、アプリケーションコードで常にダウンキャストされないようにします(エラーが発生しやすくなります)。
基本的に、XMLやJSON、またはその他のデータ交換フォーマットを使用してオブジェクトを渡すことについて話している。どのような種類のオブジェクトが渡されているかを正確に把握しているため、ダウンキャストについては、一般的なメッセージングシステムAPIで既に処理されているため、説明する必要はありません。
私はシステムAPIが次のようになっていると想定しています:
GeneralObject* getObject(Message *message);
次のようになります。
GeneralObject* _getObject(Message *message); // the _ is just to indicate this is a private function that shouldn't be used outside of this module
// these raise exceptions if the object doesn't exist or return null or whatever
Person* getPerson(Message *message);
Place* getPlace(Message *message);
コード内で基本クラスを返すジェネリック関数を使用することは決してありません。派生クラスを返すコードを常に使用し、APIにダウンキャストできない場合はエラーを処理または発生させます。
この場合のダウンキャストは、基本的にオブジェクトの解析またはシリアル化解除に失敗しています。
明らかに、それが常に悪いことであるならば、言語が操作をサポートする必要さえないでしょう。メッセージキューオブジェクトへのキャストを実際に作成する必要がありますが、ダウンキャストによってコードが大幅に簡略化されるため、シリアル化/メッセージングは大きな例外です。その場合、テンプレートはしばしば役立ちます。
ダウンキャストが避けられないことが多い他の状況は、 equals(Object obj) オーバーライドにあります。その特定のシグネチャは、公開され、広く使用されているインターフェイスの一部だからです。
はい、ダウンキャストは常に悪いです。はい、時々、代替案がより悪いシナリオ(メッセージング構成など)に出くわします。
そしてもちろん「悪化」は主観的です。一部のシナリオでは、ダウンキャストの脆弱性は非常に許容できません。また、デザインのシンプルさや読みやすさが優先される場合もあります。他の設計上の決定と同様に、これは状況に応じて評価する必要があるトレードオフです。