我正在写一个工具,使用户可以通过更改设置然后流传输信息来与一些硬件进行交互。

为此,我有几个正在运行的线程:EquipmentInterfaceDataProcessor通过Queue连接。
EquipmentInterface线程具有更改设备设置(例如RotateRefocus)的方法,并将结果信息(CurrentAngleCurrentFocalDistance)添加到Queue中。一旦设置正确,就可以使用StartStreamingStopStreaming的方法,一旦开始流传输,来自设备的数据将被打包并添加到队列中。

放在队列中的所有信息均来自单个BaseMessage类,该类包括消息类型的指示。然后,我获得了 Angular ,焦距,流的开始和结束以及当然数据本身的消息类型。
DataProcessor侦听队列的另一端,并根据当前 Angular /焦距来处理后续数据。

现在,问题是,我在数据处理器中有一个函数,该函数使用switch语句对传入的消息进行类型检查。然后将这些消息向下转换为适当的类型,并传递给适当的处理程序。实际上,不仅有一个DataProcessor在侦听单个队列,而且实际上在多个队列上有多个侦听器(有些存储在磁盘上,有些则在gui上显示信息)。每次添加一些信息时,我都必须创建一个新的BaseMessage派生类,向该基类添加一个新类型,然后更新每个使用者中的switch语句以应对新消息。

我觉得关于这种体系结构的某些事情是错误的,最近我阅读了很多有关向下转换的内容。从我所看到的,普遍的共识似乎是what I'm doing is a bad code smell。我见过a suggestion which use Boost,但是它们看起来比我的switch语句还干净(也许我遗漏了什么?)。

所以我的问题是:我应该尝试避免使用交换语句/向下转换解决方案吗?

我的实现是在C++ / CLI中进行的,因此我追求的是.net或C++解决方案。

编辑-根据iammilind和stfaanv的评论,这是您所建议的事情:

class QueuedItem
{
public:
    QueuedItem() { }
    virtual ~QueuedItem() { }

};

class Angle : public QueuedItem
{
public:
    Angle() {}
    virtual ~Angle() { }
};

class FocalLength : public QueuedItem
{
public:
    FocalLength() {}
    virtual ~FocalLength() { }
private:

};


class EquipmentHandler
{
protected:
    virtual void ProcessAngle(Angle* angle) {};
    virtual void ProcessFocalLength(FocalLength* focalLength) {};

public:
    void ProcessMessages(QueuedItem* item)
    {
        Angle* pAngle = dynamic_cast<Angle*>(item);
        if( pAngle != NULL )
        {
            ProcessAngle(pAngle);
        }
        FocalLength* pFocalLength = dynamic_cast<FocalLength*>(item);
        if( pFocalLength != NULL )
        {
            ProcessFocalLength(pFocalLength);
        }

    }
};

class MyDataProcessor : public EquipmentHandler
{
protected:
    virtual void ProcessAngle(Angle* angle) override { printf("Processing Angle"); }
    virtual void ProcessFocalLength(FocalLength* focalLength) override { printf("Processing FocalLength"); };
};


int _tmain(int argc, _TCHAR* argv[])
{

    // Equipment interface thread...
    FocalLength* f = new FocalLength();
    QueuedItem* item = f; // This gets stuck onto the queue

    // ...DataProcessor thread (after dequeuing)
    QueuedItem* dequeuedItem = item;

    // Example of a DataProcessor implementation.
    // In reality, this would
    MyDataProcessor dataProc;
    dataProc.ProcessMessages(dequeuedItem);

    return 0;
}

...并且可以简化吗? ProcessMessages有点笨拙,但这是我可以看到的唯一方法,而无需在基础类中使用switch语句和某种枚举的消息类型标识符。

最佳答案

您可以尝试访客设计模式:http://en.wikipedia.org/wiki/Visitor_pattern

每个DataProcessor都将从BaseVisitor类继承,该类定义用于处理每种Message的虚拟方法。基本上,这些方法只是noop。

定义新的消息类型时,您需要在BaseVisitor中添加一个新的虚拟方法,该方法具有此消息类型的noop实现。然后,如果子DataProcessor类要处理此消息类型,则仅在此DataProcessor中覆盖虚拟方法。其他所有DataProcessor保持不变。

    #include <iostream>


    class FocalLength;
    class Angle;
    class EquipmentVisitor;

    class QueuedItem
    {
    public:
            QueuedItem() { }
            virtual ~QueuedItem() { }

            virtual void AcceptVisitor(EquipmentVisitor& visitor) = 0;
    };

    class EquipmentVisitor
    {
    public:
            virtual ~EquipmentVisitor() {}

            virtual void Visit(FocalLength& item) {}
            virtual void Visit(Angle& item)       {}

            void ProcessMessages(QueuedItem* item)
            {
                    item->AcceptVisitor(*this);
            }
    };

    class Angle : public QueuedItem
    {
    public:
            Angle() {}
            virtual ~Angle() { }

            void AcceptVisitor(EquipmentVisitor& visitor) { visitor.Visit(*this); }
    };

    class FocalLength : public QueuedItem
    {
    public:
            FocalLength() {}
            virtual ~FocalLength() { }

            void AcceptVisitor(EquipmentVisitor& visitor) { visitor.Visit(*this); }
    private:

    };

    class MyDataProcessor : public EquipmentVisitor
    {
    public:
            virtual ~MyDataProcessor() {}

            void Visit(Angle& angle)             { std::cout << "Processing Angle" << std::endl; }
            void Visit(FocalLength& focalLength) { std::cout << "Processing FocalLength" << std::endl; }
    };


    int main(int argc, char const* argv[])
    {
            // Equipment interface thread...
            FocalLength* f    = new FocalLength();
            QueuedItem*  item = f; // This gets stuck onto the queue

            // ...DataProcessor thread (after dequeuing)
            QueuedItem* dequeuedItem = item;

            // Example of a DataProcessor implementation.
            // In reality, this would
            MyDataProcessor dataProc;
            dataProc.ProcessMessages(dequeuedItem);

            return 0;
    }

关于c++ - 通过队列传递信息时,如何避免向下转换?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10101443/

10-11 05:20