我如何处理行为组合?
我正在考虑验证各种格式的实数的问题,因为这与我在设计中面临的问题非常相似。
实数可能有不同的格式组合,例如: 1. 正面有/无标志 2. 有/没有小数点(如果没有小数点,那么小数点位数也许可以事先约定) 3. 以 10 为底或以 16 为底
我们需要考虑到每种组合,因此有 2x2x2=8 种组合。 您可以看到,随着每个新条件的施加,复杂性呈指数级增加。
在面向对象设计中,您通常会为每种数字格式分配一个类(例如,在本例中,我们有 8 个类),并且每个类都有一个单独的验证函数。 然而,随着每一个新的条件,你必须将所需的课程数量增加一倍,这很快就会变成一场噩梦。
在过程编程中,您使用 3 个标志(即 has_sign、has_decimal_point 和 number_base)来标识您正在验证的实数的属性。 您有一个用于验证的函数。 在那里,您可以使用标志来控制其行为。
// This is part of the validation function
如果(有符号)
check_sign();
for (int i = 0; i < len; i++)
{
if (有小数点)
// 检查 number[i] 是否为 '.' 如果是的话,做点什么。 如果没有,请继续
if (number_base = BASE10)
// number[i] must be between 0-9
else if (number_base = BASE16)
// number[i] must be between 0-9, A-F
}
同样,由于函数中充斥着 if 语句和标志,复杂性很快就会失控。
我确信您以前遇到过这种性质的设计问题 - 许多独立的差异导致了行为的差异。 我很想知道您如何能够在不使代码完全无法维护的情况下实现解决方案。
像桥接模式这样的东西会有帮助吗?
I am considering the problem of validating real numbers of various formats, because this is very similar to a problem I am facing in design.
Real numbers may come in different combinations of formats, for example:
1. with/without sign at the front
2. with/without a decimal point (if no decimal point, then perhaps number of decimals can be agreed beforehand)
3. base 10 or base 16
We need to allow for each combination, so there are 2x2x2=8 combinations. You can see that the complexity increases exponentially with each new condition imposed.
In OO design, you would normally allocate a class for each number format (e.g. in this case, we have 8 classes), and each class would have a separate validation function. However, with each new condition, you have to double the number of classes required and it soon becomes a nightmare.
In procedural programming, you use 3 flags (i.e. has_sign, has_decimal_point and number_base) to identify the property of the real number you are validating. You have a single function for validation. In there, you would use the flags to control its behaviour.
// This is part of the validation function
if (has_sign) check_sign();
for (int i = 0; i < len; i++) { if (has_decimal_point) // Check if number[i] is '.' and do something if it is. If not, continue
if (number_base = BASE10)
// number[i] must be between 0-9
else if (number_base = BASE16)
// number[i] must be between 0-9, A-F
}
Again, the complexity soon gets out of hand as the function becomes cluttered with if statements and flags.
I am sure that you have come across design problems of this nature before - a number of independent differences which result in difference in behaviour. I would be very interested to hear how have you been able to implement a solution without making the code completely unmaintainable.
Would something like the bridge pattern have helped?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
不不不不不。 最多,您将拥有一个用于表示数字输入的类型(以防
String
无法实现); 另一种是实数(在大多数语言中,你会选择一种内置类型,但无论如何); 和一个Parser类,它具有获取数字输入并将其转换为实数的知识。更一般地说,行为的一种差异本身并不会自动映射到一个类。 它可以只是类中的一个属性。 最重要的是,应该正交地对待行为。
如果(想象你编写自己的解析器)你可能有符号或没有符号,小数点或没有小数点,十六进制或没有,你有三个独立的复杂性来源,并且可以找到某处的三段代码,分别处理其中一个问题; 但在任何地方都无法找到 2^3 = 8 段以显式方式处理不同组合的不同代码。
想象一下添加一个新的选择:突然,您想起数字可能有一个“e”(例如 2.34e10)并且希望能够支持它。 通过正交策略,您将拥有又一个独立的复杂性来源,即第四个。 按照你的策略,8个病例会突然变成16个! 显然是不行的。
No no no no no. At most, you'd have a type for representing Numeric Input (in case
String
doesn't make it); another one for Real Number (in most languages you'd pick a built-in type, but anyway); and a Parser class, which has the knowledge to take a Numeric Input and transform it into a Real Number.To be more general, one difference of behaviour in and by itself doesn't automatically map to one class. It can just be a property inside a class. Most importantly, behaviours should be treated orthogonally.
If (imagining that you write your own parser) you may have a sign or not, a decimal point or not, and hex or not, you have three independent sources of complexity and it would be ok to find three pieces of code, somewhere, that treat one of these issues each; but it would not be ok to find, anywhere, 2^3 = 8 different pieces of code that treat the different combinations in an explicit way.
Imagine that add a new choice: suddenly, you remember that numbers might have an "e" (such as 2.34e10) and want to be able to support that. With the orthogonal strategy, you'll have one more independent source of complexity, the fourth one. With your strategy, the 8 cases would suddenly become 16! Clearly a no-no.
我不知道为什么您认为面向对象的解决方案将涉及每个数字模式的类。 我的面向对象解决方案是使用正则表达式类。 如果我是程序性的,我可能会使用标准库 strtod() 函数。
I don't know why you think that the OO solution would involve a class for each number pattern. My OO solution would be to use a regular expression class. And if I was being procedural, I would probably use the standard library strtod() function.
您需要一个解析器,请使用一个:
另外: http://en.wikipedia.org/wiki/Parser_generator
现在该怎么做我处理这类问题的复杂性? 好吧,如果可以的话,我会重新制定。
在您的情况下,使用解析器生成器(或正则表达式)就是使用 DSL(域特定语言),这是一种更适合您正在处理的问题的语言。
设计模式和 OOP 很有用,但绝对不是每个问题的最佳解决方案。
You're asking for a parser, use one:
Also: http://en.wikipedia.org/wiki/Parser_generator
Now how do I handle complexity for this kind of problems ? Well if I can, I reformulate.
In your case, using a parser generator (or regular expression) is using a DSL (Domain Specific Language), that is a language more suited to the problem you're dealing with.
Design pattern and OOP are useful, but definitely not the best solution to each and every problem.
抱歉,因为我使用 vb,所以我所做的是一个基本函数,然后我结合了一个评估器函数
所以我会按照我的方式伪造代码
,等等,由你来弄清楚如何执行二进制和八进制
Sorry but since i use vb, what i do is a base function then i combine a evaluator function
so ill fake code it out the way i have done it
and so forth up to you to figure out how to do binary and octal
你不会用锤子杀死苍蝇。
我真的觉得使用面向对象的解决方案来解决你的问题是一种极端的杀伤力。 仅仅因为您可以设计面向对象的解决方案,并不意味着您必须强迫这样的解决方案解决您遇到的每个问题。
根据我的经验,几乎每次很难找到问题的 OOD 解决方案时,都可能意味着 OOD 不合适。 OOD只是一个工具,它不是上帝本身。 它应该用于解决大规模问题,而不是您提出的问题。
因此,为了给您一个实际的答案(正如上面有人提到的):使用正则表达式,除此之外的每个解决方案都只是一种矫枉过正。
如果您坚持使用 OOD 解决方案......那么,由于您提供的所有格式都是彼此正交的,我认为没有必要为每种可能的组合创建一个类。 我将为每种格式创建一个类,并通过每个格式传递我的输入,在这种情况下,复杂性将线性增长。
You don't kill a fly with a hammer.
I realy feel like using a Object-Oriented solution for your problem is an EXTREME overkill. Just because you can design Object-Oriented solution , doesn't mean you have to force such one to every problem you have.
From my experience , almost every time there is a difficulty in finding an OOD solution to a problem , It probably mean that OOD is not appropiate. OOD is just a tool , its not god itself. It should be used to solve large scale problems , and not problems such one you presented.
So to give you an actual answer (as someone mentioned above) : use regular expression , Every solution beyond that is just an overkill.
If you insist using an OOD solution.... Well , since all formats you presented are orthogonal to each other , I dont see any need to create a class for every possible combination. I would create a class for each format and pass my input through each , in that case the complexity will grow linearly.