我有一个while (!Queue.empty())
循环来处理元素队列。有一系列模式匹配器从最高优先级到最低优先级顺序。匹配模式时,将从队列中删除相应的元素,并从顶部重新开始匹配(以便最高优先级的匹配器有机会先行动)。
所以现在它看起来像这样(简化版):
while (!Queue.empty())
{
auto & Element = *Queue.begin();
if (MatchesPatternA(Element)) { // Highest priority, since it's first
// Act on it
// Remove Element from queue
continue;
}
if (MatchesPatternB(Element)) {
// Act on it
// Remove Element from queue
continue;
}
if (MatchesPatternC(Element)) { // Lowest priority, since it's last
// Act on it
// Remove Element from queue
continue;
}
// If we got this far, that means no pattern was matched, so
// Remove Element from queue
}
这有效,但我想以某种方式重构此循环以删除关键字continue
的使用。
为什么呢?因为如果我想将模式匹配外包给外部函数,它显然会中断。 E.g。
void ExternalMatching(...)
{
if (MatchesPatternB(Element)) {
// Act on it
// Remove Element from queue
continue; // This won't work here
}
}
while (!Queue.empty())
{
auto & Element = *Queue.begin();
if (MatchesPatternA(Element)) {
// Act on it
// Remove Element from queue
continue;
}
ExternalMatching(...);
if (MatchesPatternC(Element)) {
// Act on it
// Remove Element from queue
continue;
}
// If we got this far, that means no pattern was matched, so
// Remove Element from queue
}
我不想写if (ExternalMatching(...)) { ... continue; }
这样的重复if语句,我宁愿找到一种更清晰的方式来表达这种逻辑。
这个简化的示例可能会使模式匹配更加通用,而不是具有不同的MatchesPatternA
,MatchesPatternB
,MatchesPatternC
等功能。但在我的情况下,模式非常复杂,我还没准备好对它们进行概括。所以我想保留那部分,分开的功能。
有什么优雅的想法吗?谢谢!
答案 0 :(得分:3)
我建议使用一个执行模式匹配的函数(但不对结果起作用),然后使用一组作用于不同选项的函数:
enum EventType {
A, B, C //, D, ...
};
while (!queue.empty()) {
auto & event = queue.front();
EventType e = eventType(event); // Internally does MatchesPattern*
// and returns the match
switch (e) {
case A:
processA(event);
break;
case B:
processB(event);
通过这种方式,您可以清楚地将匹配与处理分开,循环只是一个简单的调度程序
答案 1 :(得分:2)
考虑一个界面:
class IMatchPattern
{
public:
virtual bool MatchesPattern(const Element& e) = 0;
};
然后,您可以组织一个实现IMatchPattern的对象容器,以允许迭代访问每个模式匹配方法。
答案 2 :(得分:2)
如果您有权访问C ++ 11,我想提出另一种解决方案。 Basicaly我创建了一个可以在运行时调整的处理程序和操作的容器。根据您的要求,它可能是您的设计的专业或con。这是:
#include <functional>
typedef std::pair<std::function<bool(const ElementType &)>,
std::function<void(ElementType &)> > HandlerData;
typedef std::vector<HandlerData> HandlerList;
HandlerList get_handlers()
{
HandlerList handlers;
handlers.emplace_back([](const ElementType &el){ return MatchesPatternA(el); },
[](ElementType &el){ /* Action */ });
handlers.emplace_back([](const ElementType &el){ return MatchesPatternB(el); },
[](ElementType &el){ /* Action */ });
handlers.emplace_back([](const ElementType &el){ return MatchesPatternC(el); },
[](ElementType &el){ /* Action */ });
return handlers;
}
int main()
{
auto handlers = get_handlers();
while(!Queue.empty()) {
auto &Element = *Queue.begin();
for(auto &h : handlers) {
// check if handler matches the element
if(h.first(Element)) {
// act on element
h.second(Element);
break;
}
}
// remove element
Queue.pop_front();
}
}
答案 3 :(得分:1)
您可以将ExternalMatching
更改为返回bool
,表示已完成处理。通过这种方式,调用者可以在必要时继续进行评估:
bool ExternalMatching(...)
{
if (MatchesPatternB(Element) {
// Act on it
// Remove Element from queue
return true;
}
return false;
}
现在你可以这样称呼它:
if (ExternalMatchin1(...)) continue;
if (ExternalMatchin2(...)) continue;
...
if (ExternalMatchingN(...)) continue;
答案 4 :(得分:1)
好的,我最终重写了类似于此的循环。
巨大的感谢和归功于Yuushi,dasblinkenlight,DavidRodríguez的帮助;这个答案是基于他们的答案的组合。
bool ExternalMatching(...)
{
bool Match;
if ((Match = MatchesPatternX(Element))) {
// Act on it
} else if ((Match = MatchesPatternY(Element))) {
// Act on it
}
return Match;
}
while (!Queue.empty())
{
auto & Element = Queue.front();
if (MatchesPatternA(Element)) { // Highest priority, since it's first
// Act on it
} else if (MatchesPatternB(Element)) {
// Act on it
} else if (ExternalMatching(...)) {
} else if (MatchesPatternC(Element)) { // Lowest priority, since it's last
// Act on it
}
// Remove Element from queue
}
现在,我知道还有进一步改进的空间,请参阅Mateusz Pusz和Michael Sh的答案。但是,这足以回答我原来的问题,现在也可以。我会考虑将来改进它。
如果您想要查看真实代码(非简化版),请参阅此处:
再次感谢大家!
答案 5 :(得分:0)
我想建议一个Factory函数,它将接受Element并创建一个合适的处理程序并将接口指针返回给处理程序。
while (!Queue.empty())
{
auto & Element = *Queue.begin();
// get the appropriate handler object pointer e.g.
IPatternHandler *handler = Factory.GetHandler(Element);
handler->handle();
// clean up handler appropriately
}