虚拟呼叫与类型检查的另一个例子 [英] Another example of virtual calls vs. type-checking

查看:126
本文介绍了虚拟呼叫与类型检查的另一个例子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题



我发誓,每次我把它捣烂成我的大脑,我应该使用虚拟电话与类型检查(例如:



 如果(obj是富)

,否则如果(obj是酒吧)
..

...我想出了一个例子,我不知道如何实现前



我实现了一个串行端口的分组协议的一些伪代码会解释这个最好的:

  OnDataReceived:
RcvPacket p = RcvPacket.ReadPacket(COMPORT); //调用工厂方法
如果(p是RcvPacketFoo)
OnFoo();
如果(p是RcvPacketBar)
的OnBar();

OnFoo:
募集富事件
的OnBar:
加薪酒吧事件

基本上,ReadPacket是一个工厂方法基类确定所接收的分组的类型,并通过缓冲器到正确的派生类型的构造。在此之后,我需要提高的情况下,根据数据包的类型。我怎么能做到这一点,而无需使用运营商?是我的方法声音/理智?






解决方案



访问者模式,当然!由于巴勃罗·罗密欧



在这种情况下,我做控制器,调用该工厂方法,是游客。我的结果是:



 公共接口IPacketHandler {
无效手柄(FooPacket P);
无效手柄(BarPacket P);
}

公共类控制器:IPacketHandler {
OnDataReceived(){
RcvPacket P = RcvPacket.ReadPacket(水果盘); //调用工厂方法
p.Handle(本); // ***虚拟呼叫:第一个派遣***
}

//注意使用显式接口实现这里。
IPacketHandler.Handle(FooPacket P){
OnFoo();
}
IPacketHandler.Handle(BarPacket P){
的OnBar();
}
}

公共抽象类RcvPacket {
公共静态RcvPacket ReadPacket(...){...} //工厂方法
公无效句柄(IPacketHandler处理);
}
公共类FooPacket:RcvPacket {
公共覆盖无效的句柄(IPacketHandler处理器){
handler.Handle(本); // ***重载电话:第二个调度***
}
}
公共类BarPacket:RcvPacket {
公共覆盖无效的句柄(IPacketHandler处理器){
handler.Handle(本); // ***重载电话:第二个调度***
}
}

在这里好玩的事,是通过明确实现访问者接口,处理通话基本上是隐藏的。从 MSDN




这是实现一个接口可以显式实现该接口的成员的类。当一个部件被明确实现的,它不能被通过一个类的实例访问,但仅通过该接口的一个实例。



解决方案

好了,考虑到你可能不希望每个包里面很多额外的逻辑,您可以通过双重分派完成它。



在这种情况下,我可能会创建一个接口,如:

 公共接口IPacketEvents 
$ { b $ b空开(富富);
无效(条状栏);
}



我假设你拥有所有数据包的基类。在这里面,我就会宣布:

 公共抽象无效RaiseUsing(IPacketEvents事件); 

和包装的每个子类将实施以下内容:

 公共覆盖无效RaiseUsing(IPacketEvents事件)
{
events.On(本);
}

您既可以有一个新的类实现 IPacketEvents 或从调用工厂同一个类可以实现它。
在第二种情况下,您的通话将结束为:

  OnDataReceived:
RcvPacket P = RcvPacket .ReadPacket(水果盘); //调用工厂方法
p.RaiseUsing(本);



使用这种类型发稿时,你得到的,是每个类型,调用相应的方法,因为它知道来称呼哪一个。
它可能会混淆了一下,我用同样的开名称的所有方法,但事实并非完全必要的。他们可能是OnFoo()和OnBar的()。



这类型的行为也是在的 Visitor模式


Problem

I swear, every time I get it pounded into my brain that I should be using virtual calls vs. type-checking (eg:

if (obj is Foo)
   ...
else if (obj is Bar)
   ...

... I come up with another example where I don't know how to implement the former.

I'm implementing a packetized protocol over a serial port. Some pseudo-code will explain this best:

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

Basically, ReadPacket is a factory method in the base class that determines the type of packet being received, and passes the buffer to the correct derived-type constructor. After this, I need to raise an event, depending on the type of packet. How can I do this without using the is operator? Is my method sound/sane?


Solution

The Visitor Pattern, of course! Thanks Pablo Romeo.

In this case, I made the controller, that is calling the factory method, is the visitor. My result:

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 ***
    }
}

The fun thing here, is that by explicitly implementing the visitor interface, the Handle calls are essentially hidden. From MSDN:

A class that implements an interface can explicitly implement a member of that interface. When a member is explicitly implemented, it cannot be accessed through a class instance, but only through an instance of the interface.

解决方案

Well, considering that you probably don't want much additional logic inside each packet, you can accomplish it through Double Dispatch.

In that case, I'd probably create an interface, such as:

public interface IPacketEvents 
{
    void On(Foo foo);
    void On(Bar bar);
}

I'm assuming you have a base class for all packets. In it I would declare:

public abstract void RaiseUsing(IPacketEvents events);

And each subclass of package would implement the following:

public override void RaiseUsing(IPacketEvents events) 
{
    events.On(this);
}

You could either have a new class implement the IPacketEvents or that same class from where you call the factory could implement it. In that second case, your call would end up as:

OnDataReceived:
    RcvPacket p = RcvPacket.ReadPacket(comport);   // Call factory method
    p.RaiseUsing(this);

Using this type of dispatch, what you get, is that each type, calls the corresponding method, because it "knows" which one to call. It may confuse a bit that I used the same "On" name for all methods, but that's not entirely necessary. They could be OnFoo() and OnBar().

This type of behavior is also used in the Visitor pattern.

这篇关于虚拟呼叫与类型检查的另一个例子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆