問題
私は、脳にドキドキするたびに、仮想呼び出しとタイプチェックを使用する必要があることを誓います(例:
if (obj is Foo)
...
else if (obj is Bar)
...
...前者の実装方法がわからない別の例を思いつきます。
シリアルポートを介してパケット化されたプロトコルを実装しています。いくつかの擬似コードはこれを最もよく説明します:
OnDataReceived:
RcvPacket p = RcvPacket.ReadPacket(comport); // Call factory method
if (p is RcvPacketFoo)
OnFoo();
if (p is RcvPacketBar)
OnBar();
OnFoo:
raise Foo event
OnBar:
raise Bar event
基本的に、ReadPacketは、受信するパケットのタイプを判別し、バッファーを正しい派生型コンストラクターに渡す基本クラスのファクトリメソッドです。この後、パケットの種類に応じて、イベントを発生させる必要があります。演算子を使用せずにこれを行うにはどうすればよいですか?私の方法は健全/正気ですか?is
解決
この場合、ファクトリメソッドを呼び出すコントローラーをビジターにしました。私の結果:
public interface IPacketHandler {
void Handle(FooPacket p);
void Handle(BarPacket p);
}
public class Controller : IPacketHandler {
OnDataReceived() {
RcvPacket p = RcvPacket.ReadPacket(comport); // Call factory method
p.Handle(this); // *** Virtual Call: The first dispatch ***
}
// Note the use of explicit interface implementation here.
IPacketHandler.Handle(FooPacket p) {
OnFoo();
}
IPacketHandler.Handle(BarPacket p) {
OnBar();
}
}
public abstract class RcvPacket {
public static RcvPacket ReadPacket(...) { ... } // Factory method
public void Handle(IPacketHandler handler);
}
public class FooPacket : RcvPacket {
public override void Handle(IPacketHandler handler) {
handler.Handle(this); // *** Overloaded call: The second dispatch ***
}
}
public class BarPacket : RcvPacket {
public override void Handle(IPacketHandler handler) {
handler.Handle(this); // *** Overloaded call: The second dispatch ***
}
}
ここでの楽しい点は、ビジターインターフェイスを明示的に実装することにより、Handle
呼び出しが本質的に非表示になることです。MSDNから:
インターフェイスを実装するクラスは、そのインターフェイスのメンバーを明示的に実装できます。メンバーが明示的に実装されている場合、クラスインスタンスを介してアクセスすることはできず、インターフェイスのインスタンスを介してのみアクセスできます。