gpt4 book ai didi

c++ - 检查对象类型真的总是糟糕设计的标志吗?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:35:49 25 4
gpt4 key购买 nike

我有几行文本的来源,每一行都是一条消息,代表某种类型的对象。我正在为这些行创建一个解析器,它应该将文本行作为输入并将准备好使用的对象作为输出。所以我制作了以下类层次结构:

class Message
{
public:
virtual ~Message(){};
};

class ObjectTypeA : public Message
{/*...*/};
class ObjectTypeB : public Message
{/*...*/};
class ObjectTypeC : public Message
{/*...*/};

下面是它的使用方式:

std::shared_ptr<Message> parseLine(std::string& line);

void doWork()
{
std::string line;
while(getLine(line))
{
std::shared_ptr<Message> object=parseLine(line);
if(dynamic_cast<ObjectTypeA*>(object.get()))
doSomethingA(*static_cast<ObjectTypeA*>(object.get()));
else if(dynamic_cast<ObjectTypeB*>(object.get()))
doCompletelyUnrelatedProcessing(*static_cast<ObjectTypeB*>(object.get()));
else if(dynamic_cast<ObjectTypeC*>(object.get()))
doSomethingEvenMoreDifferent(*static_cast<ObjectTypeC*>(object.get()));
}
}

这里的解析器是一个库函数,对象事先并不知道它们将如何被处理。因此,我无法将处理代码放入 Message 实现的虚函数中。

但是this question中的很多答案说如果需要检查对象的类型,这是设计不良的标志。但我似乎看不出这里有什么不好。有没有更好的方法来组织解决方案?

最佳答案

首先,它并不总是是糟糕设计的标志。在“好”或“坏”设计等“软”事物中几乎没有绝对值。尽管如此,它确实经常表明,由于以下一个或多个原因,不同的方法会更可取:可扩展性、易于维护、熟悉度等。

在您的特定情况下:在没有类型切换或膨胀/污染类接口(interface)的情况下使任意类特定处理成为可能的标准方法之一是使用 Visitor pattern .您创建一个通用的 MessageVisitor 接口(interface),教 Message 子类调用它,并在需要处理它们的任何地方实现它:

class MessageVisitor;

class Message
{
public:
virtual ~Message(){};

virtual void accept(MessageVisitor &visitor) = 0;
};

class ObjectTypeA : public Message
{
void accept(MessageVisitor &visitor) override
{ visitor.visit(*this); }
/*...*/
};

class ObjectTypeB : public Message
{
void accept(MessageVisitor &visitor) override
{ visitor.visit(*this); }
/*...*/
};

class ObjectTypeC : public Message
{
void accept(MessageVisitor &visitor) override
{ visitor.visit(*this); }
/*...*/
};

class MessageVisitor
{
public:
virtual void visit(ObjectTypeA &subject) {}

virtual void visit(ObjectTypeB &subject) {}

virtual void visit(ObjectTypeC &subject) {}
};

然后你会像这样使用它:

void doWork()
{
struct DoWorkMessageVisitor : MessageVisitor
{
void visit(ObjectTypeA &subject) override { doSomethingA(subject); }

void visit(ObjectTypeB &subject) override { doSomethingB(subject); }

void visit(ObjectTypeC &subject) override { doSomethingC(subject); }
};
std::string line;
while(getLine(line))
{
std::shared_ptr<Message> object=parseLine(line);
DoWorkMessageVisitor v;
object->accept(v);
}
}

如有必要,请随意使用 const 重载等对其进行自定义。

请注意,accept 不能在基类中实现,因为在调用visit 时需要正确的*this 类型。 是类型开关“移动”的地方。


另一种方法是使 MessageVisitor 中的 visit 函数成为纯虚拟的,而不是空的。然后,如果您需要添加新的消息类型,它会自动强制您更新所有发生此类特定类型处理的地方。

关于c++ - 检查对象类型真的总是糟糕设计的标志吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30074805/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com