用什么代替巨型switch语句?

时间:2009-03-18 18:38:59

标签: c++ templates switch-statement chain-of-responsibility

我有一个解析一些模板文件的代码,当它找到一个占位符时,它会用一个值替换它。类似的东西:

<html>
<head>
    <title>%title%</title>
</head>
<body bgcolor="%color%">
...etc.

在代码中,解析器找到这些,调用此函数:

string getContent(const string& name)
{
    if (name == "title")
        return page->getTitle();
    else if (name == "color")
        return getBodyColor();
    ...etc.
}

然后用返回值替换原始占位符。

在实际情况中,它不是虚拟网页,并且可以发生许多(50+)个不同的占位符。

我的代码是C ++,但我猜这个问题存在于任何语言中。我猜它更多的是关于算法和OO设计。唯一重要的是必须编译它,即使我希望我没有任何动态/评估代码。

我虽然关于实施责任链模式,但似乎不会改善这种情况。

更新:我也关注另一个帖子中的this comment。我应该关心它吗?

6 个答案:

答案 0 :(得分:25)

使用将标记名称映射到标记处理程序的字典。

答案 1 :(得分:4)

你想要replace conditional with polymorphism。大致是:

string getContent(const string& name) {
    myType obj = factory.getObjForName(name);
    obj.doStuff();
}

doStuff重载的地方。

答案 2 :(得分:3)

你考虑过XSLT吗?它非常适合这种事情。我开发了一个完全相同的内容管理系统,发现XSLT非常有效。解析器为您完成了很多工作。

更新:史蒂文的评论提出了一个重点 - 如果你决定采用XSLT路线,你会希望你的模板是有效的XHTML。 另外 - 我会使用不同的分隔符来替换令牌。不太可能自然发生的事情。我用#!PLACEHOLDER#!在我的CMS中。

答案 3 :(得分:3)

我将结合3个想法:

  1. (来自Steven Hugig):使用一个工厂方法,为每个选择器提供不同的类。
    • (来自Neil Butterworth):在工厂内部,使用字典,以便摆脱大switch(){}
    • (我的):为每个处理程序类添加一个setup()方法,将自身(或新的类实例)添加到字典中。
  2. 解释一下:

    • 创建一个具有static dict的抽象类,以及使用选择器字符串注册实例的方法。
    • 在每个子类上setup()方法使用超类'dict
    • 注册自己
    • 工厂方法只是字典阅读

答案 4 :(得分:2)

不是解析,而是尝试将模板读入字符串然后只执行替换。

fileContents = fileContents.Replace("%title%", page->getTitle());
fileContents = fileContents.Replace("%color%", getBodyColor());

答案 5 :(得分:2)

作为"Uncle" Bob Martin mentioned in a previous podacast with Joel and Jeff,您提出的几乎任何内容都将基本上复制大转换语句。

如果您觉得更好地实施上面选择的解决方案之一,那很好。它可能会使您的代码更漂亮,但在封面下,它基本上是等效的。

重要的是确保只有一个big switch语句实例。你的switch语句或字典应该确定哪个类处理这个标记,然后应该使用多态来处理后续的确定。