问题描述
在事件处理程序中,我正在响应值的更改.我可以访问旧值和新值,并希望根据更改的内容做某些事情.
In an event handler I'm responding to the change of a value. I have access to the old value and the new value and want to do certain things depending on what the change is.
每个不同的结果都会执行 X、Y 或 Z 的动作/功能的某种组合.Z 接受介于 -1 和 1 之间的参数.执行这些的顺序并不重要.
Each different outcome will do some combination of actions/functions X, Y, or Z. Z accepts a parameter between -1 and 1. Order of performing these is not important.
看看下面的逻辑网格.旧值是标签的最左边一列,新值是标签的顶行:
Look at the following logic grid. The old value is the leftmost column of labels, and the new value is the top row of labels:
New:
0 !=0
-------- -------
Old: 0 | nothing Y, Z(1)
!=0 | X, Z(-1) X, Y -- Z(0) is okay but not required for this quadrant
有什么好的方法来表示这个?
What would be a good way to represent this?
我正在使用 C# 工作,但我会接受任何语言的答案,因为这不是一个真正的语言问题——我可以翻译任何内容.
I'm working in C# but will accept answers in any language since it's not really a language question—I can translate whatever.
例子:
if (oldvalue == 0 && newvalue == 0) return;
if (oldvalue != 0) X();
if (newvalue != 0) Y();
Z(oldvalue != 0 ? -1 : 0 + newvalue != 0 ? 1 : 0);
我想这看起来不错,但还有其他方法可以做到.
I suppose that looks pretty good, but there are other ways it could be done.
int which = (oldvalue == 0 ? 0 : 1) + (newvalue == 0 ? 0 : 2)
switch (which) {
case 1:
X(); Z(-1);
break;
case 2:
Y(); Z(1);
break;
case 3:
X(); Y();
break;
}
这实际上比我正在处理的情况要简单一些.如果 oldvalue 和 newvalue 不为零且彼此相等,则将 newvalue 视为 0.
This is actually a slightly simpler case than what I'm dealing with. In the case that oldvalue and newvalue are nonzero and equal to each other, treat newvalue as if it was 0.
随意回答给定或附加限制.还有一点点,但我认为开始时太多了.如果事后看起来很有趣,我将在此处或在新问题中介绍其余部分.
Feel free to answer as given or with this additional constraint. There's still a little bit more but I think it's too much to start off with. If things seem interesting afterward, I'll present the rest either here or in a new question.
我想我是在问这个问题,因为我经常会遇到这些逻辑网格的东西,而且它们并不总是 2x2,有时它们会更大一些.很高兴注意到我可以处理一些带有整个条纹"的响应,比如注意到每次 oldvalue != 0 时 X 都会完成,但似乎我开始遇到一种模式,需要一些表达逻辑来处理它更普遍,而不是费力地将其变成 if then else 语句.我的意思是,如果我能提供一种逻辑网格并让编译器找出处理它的最佳方法,那将是非常酷的.
I guess I'm asking the question because I end up with these logic grid things often, and they aren't always 2x2, sometimes they're a bit bigger. It's nice to notice that I can handle some responses with entire "stripes" like noticing that X is done every time the oldvalue != 0, but it seems like I'm starting to run into a pattern that begs for some expressive logic to handle it more generally instead of laboriously turning it into if then else statements. I mean, it would be really cool if I could provide a sort of grid of logic and let the compiler figure out the best way to handle it.
只是进行一些疯狂的头脑风暴:
Just doing some wild brainstorming:
Conditions:
oldvalue == 0 ? 0 : 1
newvalue == 0 ? 0 : 2
Actions:
X = {false, true, false, true}
Y = {false, false, true, true}
Z(-1) = true where condition = 1
Z(1) = true where condition = 2
你有什么想法?我会奖励任何物质参与.
What are your ideas? I'll reward any material involvement at all.
推荐答案
让我们换个角度看你的问题. 在设计一段代码时,我尝试应用以下原则:
Let's look at your problem from another point of view. When designing a body of code, I try to apply the following principle:
- 改正.
- 说清楚.
- 简明扼要.
- 快点.... 按此顺序.
所有这些,在某种程度上,都是主观的.然而,通情达理的人往往会找到共同点——而且往往对他们的对立面有更多的共识.但除此之外......
All of these, to one extent or another, are subjective. However, reasonable people tend to find common ground - and there's often more agreement about their opposites. But that aside...
这里的首要任务是确保您的代码能够正常工作.显然,有多种实现方式可以实现这一点 - 但我还要补充一点,重要的是要易于证明实现是正确的.实现这一点的一种方法是让代码读起来更像规范(稍后会详细介绍).
The first priority here is making sure that your code will work correctly. Clearly, there are multiple implementation that achieve this - but I would also add that it's important that it be easy to demonstrate that the implementation is correct. One way of achieving this is to make the code read more like the spec (more on this later).
第二个优先事项是确保将来当开发人员(包括原作者!)查看此代码时,他们将能够立即理解它在做什么.实现越复杂(阅读:fancy),开发人员就越难立即理解代码在做什么.
The second priority is to make sure that in the future, when a developer (including the original author!) looks at this code they'll be able to understand what it's doing right away. The more sophisticated (read: fancy) the implementation, the harder it is for a developer to immediately understand what the code is doing.
第三个优先级 - 简短、简洁的代码,部分与前两个相反. 想要使代码更简洁,可能会导致您使用比实际更复杂的结构实际需要解决问题.虽然保持代码简短很重要,但我们不应该通过使其难以理解的密集来做到这一点.
The third priority - short, concise code, is one that partially stands in opposition to the first two. A desire to make the code more concise, may lead you to use more complex constructs than are actually necessary to solve the problem. While it's important to keep the code short, we shouldn't do this by making it unintelligibly dense.
最后的优先级 - 性能 - 仅在重要时才重要. 我的意思是,除非您已执行分析并确定它是您系统中的瓶颈.
The last priority - performance - only matters when it matters. By this, I mean that you shouldn't complicate the implementation from the point of view of performance unless you've performed profiling and identified it as bottleneck in your system.
既然我们已经了解了应该推动我们决策的原则,让我们将它们应用到手头的问题上.您已经提供了关于代码应该如何执行的非常清晰的规范表现.让我们尝试遵守它们:
So now that we've looked at the principles that should drive our decisions, let's apply them to the problem at hand. You've provided a very clear specification of how the code is supposed to behave. Let's try to adhere to them:
void YourMethod( int oldValue, int newValue )
{
bool oldValueNonZero = oldValue != 0;
bool newValueNonZero = newValue != 0;
if( oldValueNonZero ) { X(); }
if( newValueNonZero ) { Y(); }
if( oldValueNonZero && newValueNonZero ) { Z(); }
}
那么我为什么喜欢这个特殊的实现.让我们分解一下.
首先,请注意,我选择创建临时布尔值来捕获测试旧/新值是否为非零的结果.通过捕获这些值,我避免了多次执行计算,并且还使代码更具可读性(见下文).
First, note that I've chosen to create temporary boolean to capture the result of testing the old/new value for whether they are nonzero. By capturing these values, I avoid performing the calculation more than once, and I also make the code more readable (see below).
第二,通过选择描述性名称 oldValueNonZero
和 newValueNonZero
,我正在使实现清楚地表明我的期望.这既提高了代码的可读性,又清楚地将我的意图传达给未来必须阅读它的开发人员.
Second, by choosing the descriptive names oldValueNonZero
and newValueNonZero
I'm making the implementation clearly indicate my expectations. This both improves the readability of the code and clearly conveys my intent to future developers who have to read it.
第三,注意 if()
测试的主体包裹在 {
和 }
括号中- 这有助于减少未来对实现的更改会破坏行为的可能性 - 例如,通过意外包含一个新案例.使用单行 ifs
可以解决未来的问题.
Third, note that the body of the if()
test is wrapped in {
and }
brackets - this helps reduce that chance that future changes to the implementation will break the behavior - by accidentally including a new case, for instance. Using single-line ifs
is a recipe for future problems.
最后,我不会尝试短路比较并提前退出功能.如果性能非常重要,那么提前退出可能会很有用.但除此之外,如果只有一个退出点(1),则更容易理解方法的行为.
Finally, I don't try to short-circuit the comparison and exit the function early. If performance were extremely important, an early exit may be useful. But otherwise, it makes it easier to understand the behavior of a method if there's only one exit point(1).
这段代码是否按照规范所说的那样做?我相信是的.
是否易于阅读和理解. 至少在我看来,我会说是的.
Is it easy to read and understand. At least to my eyes, I would say yes.
这段代码是短路逻辑的最紧凑或最复杂的方法吗?几乎可以肯定不是......但在我看来,它的其他品质可以弥补这一点.
Is this code the most compact or sophisticated way of short-circuiting the logic? Almost certainly not ... but it's other qualities more than make up for that, in my opinion.
您是否喜欢这种特殊的代码结构,在某种程度上,是品味和风格的问题.但我希望我所阐述的关于我选择如何组织它的原则可以帮助你在未来做出这样的决定.
Whether you like this particular structure of code or not is, to some extent, a matter of taste and style. But I hope that the principles I've laid out about how I chose to organize it may help you make such decisions in the future.
您曾表示您有时会遇到类似的逻辑网格"问题,但案例数量更多.由于两个不同的原因,这些类型的问题可能会变得复杂:
You've indicated that you sometimes run into similar "logic-grid" problems, but ones where the number of cases are more numerous. These kinds of problems can become complicated for two separate reasons:
- 参数可以取值的数量增加 - 它们可以取一般形式
MxN
. - 维度数量增加 - 换句话说,规则中包含更多变量:
MxNxOxP...xZ
.
该问题的一个通用解决方案(如另一个响应所示)是将解决方案编码为多维矩阵 - 并为每种情况定义一组操作.但是,规则完全有可能重叠 - 为简单起见,可能希望将等效案例折叠在一起.
One generalized solution to the problem (as another response indicates), is to encode the solution as multidimensional matrix - and define a set of actions for each case. However, it's entirely possible for the rules to overlap - and it's probably desirable to collapse equivalent cases together, for simplicity.
我对处理一般情况的反应是……视情况而定.如果条件可以减少到极少数情况,那么命令式 if/else 逻辑可能仍然是解决问题的最佳方法.如果条件的数量非常多,那么使用声明性方法可能是有意义的,在这种方法中,您使用某种查找表或矩阵来对案例进行编码.
My response to dealing with the general case is ... that it depends. If the conditions can be reduced to some very small number of cases, than imperative if/else logic may still be the best way to solve the problem. If the number of conditions are very large, than it may make sense to use a declarative approach, in which you use some kind of lookup table or matrix to encode the cases.
1> - 只有一个方法退出点的原则的一个常见例外是前置条件.通过首先检查所有/任何先决条件,如果违反(退出)方法,则避免嵌套和反转逻辑更干净.
这篇关于在代码中高效地表达 2x2 逻辑网格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!