我正在为我的数据库开发一个高度专业化的搜索引擎。当用户提交搜索请求时,引擎会将搜索项拆分为数组并循环遍历。在循环内部,针对几种可能的场景检查每个搜索项以确定它可能意味着什么。当搜索项与场景匹配时,会向SQL查询添加WHERE条件。某些术语可以有多种含义,在这些情况下,引擎会构建一个建议列表,以帮助用户缩小结果范围。
除此之外:如果有人有兴趣知道,可以通过在关键字前加上前缀来改进含糊不清的术语。例如,1954年可能是一年或序列号。引擎会向用户建议这两种情况,并将搜索字词修改为年份:1954年或序列号:1954年。
在同一个循环中构建SQL查询和优化建议对我来说感觉不对,但是将它们分开会增加更多的开销,因为我必须循环遍历同一个数组两次并测试所有相同的场景两次。什么是更好的行动方案?
答案 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)
我认为有人可能认为这可能并不完全与语言无关;它也高度依赖于你想要完成的事情。如果你将多个任务放在一个循环中,使得它们不能被编译器轻松地并行化为并行环境,那么它肯定是代码味道。