在同一个循环中执行两个不同的任务是不是很糟糕?

时间:2010-01-22 15:56:31

标签: language-agnostic

我正在为我的数据库开发一个高度专业化的搜索引擎。当用户提交搜索请求时,引擎会将搜索项拆分为数组并循环遍历。在循环内部,针对几种可能的场景检查每个搜索项以确定它可能意味着什么。当搜索项与场景匹配时,会向SQL查询添加WHERE条件。某些术语可以有多种含义,在这些情况下,引擎会构建一个建议列表,以帮助用户缩小结果范围。

除此之外:如果有人有兴趣知道,可以通过在关键字前加上前缀来改进含糊不清的术语。例如,1954年可能是一年或序列号。引擎会向用户建议这两种情况,并将搜索字词修改为年份:1954年或序列号:1954年。

在同一个循环中构建SQL查询和优化建议对我来说感觉不对,但是将它们分开会增加更多的开销,因为我必须循环遍历同一个数组两次并测试所有相同的场景两次。什么是更好的行动方案?

11 个答案:

答案 0 :(得分:13)

我可能会将这两个动作分解为自己的功能。那你就有了

foreach (term in terms) {
    doThing1();
    doThing2();
}

这很干净。

答案 1 :(得分:6)

没有。不算太差。我认为循环两次会更令人困惑。

但是,如果任务彼此分离得足够多,可能会将某些任务放入函数中。

答案 2 :(得分:4)

我认为为了理论纯度添加多个循环是没有意义的,特别是考虑到如果你要针对多个场景添加一个循环,你将从O(n) - > O(N *#场景)。另一种解决方法而不涉及“上帝方法”陷阱的方法是使用一个运行单个循环并返回匹配数组的方法,另一个运行搜索匹配数组中每个元素的方法。

答案 3 :(得分:3)

使用相同的循环对我来说似乎是一个有效的优化,尝试保持两个任务的代码独立,以便在必要时可以更改此优化。

答案 4 :(得分:3)

您的方案适合构建器模式,如果每个操作相当复杂那么它可以很好地解决问题。如果您的所有逻辑都适合50行代码,那么这就是工程上的问题,但如果您有依赖管理和复杂的逻辑,那么您应该使用经过验证的设计模式来实现关注点的分离。它可能看起来像这样:

var relatedTermsBuilder = new RelatedTermsBuilder();
var whereClauseBuilder = new WhereClauseBuilder();

var compositeBuilder = new CompositeBuilder()
    .Add(relatedTermsBuilder)
    .Add(whereClauseBuilder);

var parser = new SearchTermParser(compositeBuilder);
parser.Execute("the search phrase");

string[] related = relatedTermsBuilder.Result;

string whereClause = whereClauseBuilder.Result;

支持对象如下:

public interface ISearchTermBuilder {
    void Build(string term);
}

public class SearchTermParser {
    private readonly ISearchTermBuilder builder;

    public SearchTermParser(ISearchTermBuilder builder) {
        this.builder = builder;
    }

    public void Execute(string phrase) {
        foreach (var term in Parse(phrase)) {
            builder.Build(term);
        }
    }

    private static IEnumerable<string> Parse(string phrase) {
        throw new NotImplementedException();
    }
}

答案 5 :(得分:1)

我不认为在一个循环中进行两个动作是错误的。我甚至建议制作两个从循环内部调用的方法,如:

for (...) {
   refineSuggestions(..)
   buildQuery();
}

另一方面,O(n)= O(2n)

所以不要太担心 - 这不是一种表演罪。

答案 6 :(得分:1)

我称之为代码气味,但不是很糟糕。我会将循环中的功能分开,首先放置其中一个,然后在空白行之后和/或注释另一个。

答案 7 :(得分:1)

我会把它看作是观察者模式的一个实例:每次循环都会引发一个事件,并且你想要的许多观察者都可以订阅它。当然,将它作为模式来做是过分的,但相似之处告诉我,执行两到三个或你想要多少动作就好了。

答案 8 :(得分:0)

你当然可以运行两个循环。

如果很多这是业务逻辑,你也可以在第一个循环中创建某种数据结构,然后用它来生成SQL,比如

search_objects = []
loop through term in terms
   search_object = {}
   search_object.string = term
   // suggestion & rules code
   search_object.suggestion = suggestion
   search_object.rule = { 'contains', 'term' }
   search_objects.push(search_object)

loop through search_object in search_objects
   //generate SQL based on search_object.rule

这至少可以让你不必在两个循环中执行if / then / elses,而且我认为在第一个循环之外移动SQL代码会更简洁。

答案 9 :(得分:0)

如果您在循环中所做的事情是相关的,那么很好。编写“每次迭代的东西”然后将其包装在一个循环中可能是有意义的,因为那可能是你在脑海中想到它的方式。

添加评论,如果评论太长,请查看拆分或使用简单的实用工具方法。

答案 10 :(得分:0)

我认为有人可能认为这可能并不完全与语言无关;它也高度依赖于你想要完成的事情。如果你将多个任务放在一个循环中,使得它们不能被编译器轻松地并行化为并行环境,那么它肯定是代码味道。