2

我正在考虑验证各种格式的实数的问题,因为这与我在设计中面临的问题非常相似。

实数可能有不同的格式组合,例如: 1. 前面有/没有符号 2. 有/没有小数点(如果没有小数点,那么可能可以事先约定小数位数) 3. 以 10 为底或以 16 为基数

我们需要考虑每个组合,所以有 2x2x2=8 个组合。您可以看到,随着每个新条件的施加,复杂性呈指数增长。

在 OO 设计中,您通常会为每种数字格式分配一个类(例如,在这种情况下,我们有 8 个类),并且每个类都有一个单独的验证函数。但是,对于每个新条件,您必须将所需的课程数量增加一倍,这很快就会变成一场噩梦。

在过程编程中,您使用 3 个标志(即 has_sign、has_decimal_point 和 number_base)来识别您正在验证的实数的属性。您有一个用于验证的函数。在那里,您将使用标志来控制其行为。


// 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

}

同样,复杂性很快就会失控,因为函数会被 if 语句和标志弄得杂乱无章。

我确信您之前遇到过这种性质的设计问题——许多独立的差异导致行为的差异。我很想知道您是如何在不使代码完全无法维护的情况下实现解决方案的。

像桥模式这样的东西会有帮助吗?

4

5 回答 5

4

在 OO 设计中,您通常会为每种数字格式分配一个类(例如,在这种情况下,我们有 8 个类),并且每个类都有一个单独的验证函数。

不不不不不。最多,您会有一个表示数字输入的类型(以防万一String);另一个用于实数(在大多数语言中,您会选择内置类型,但无论如何);和一个Parser类,它具有获取数字输入并将其转换为实数的知识。

更一般地说,一种行为差异本身并不会自动映射到一个类。它可以只是一个类中的一个属性。最重要的是,行为应该被正交对待。

如果(假设您编写自己的解析器)您可能有符号或没有,小数点或没有,以及十六进制或没有,您有三个独立的复杂性来源,可以在某处找到三段代码,分别处理其中一个问题;但是在任何地方都无法找到 2^3 = 8 段以明确方式处理不同组合的不同代码。

想象一下添加一个新的选择:突然,你记得数字可能有一个“e”(例如 2.34e10)并且希望能够支持它。使用正交策略,您将拥有一个更独立的复杂性来源,即第四个。以你的策略,这8个病例会突然变成16个!显然是一个禁忌。

于 2009-06-30T09:58:20.167 回答
2

我不知道您为什么认为 OO 解决方案会涉及每个数字模式的类。我的 OO 解决方案是使用正则表达式类。如果我是程序化的,我可能会使用标准库 strtod() 函数。

于 2009-06-30T09:49:56.983 回答
2

你要求一个解析器,使用一个:

另外:http ://en.wikipedia.org/wiki/Parser_generator

现在我该如何处理这类问题的复杂性?好吧,如果可以的话,我会重新制定。

在您的情况下,使用解析器生成器(或正则表达式)正在使用 DSL(域特定语言),这是一种更适合您正在处理的问题的语言。

设计模式和 OOP 很有用,但绝对不是每个问题的最佳解决方案。

于 2009-06-30T09:53:07.243 回答
0

抱歉,但是因为我使用 vb,所以我所做的是一个基本函数,然后我结合了一个评估函数,所以我会按照我的方式伪造代码

function getrealnumber(number as int){ return  getrealnumber(number.tostring) }
function getrealnumber(number as float){ return  getrealnumber(number.tostring) }
function getrealnumber(number as double){ return  getrealnumber(number.tostring) }
function getrealnumber(number as string){
if ishex(){ return evaluation()}
   if issigned(){ return evaluation()}
   if isdecimal(){ return evaluation()}
 }

等等,由你决定如何做二进制和八进制

于 2009-06-30T09:56:32.790 回答
0

你不会用锤子杀死苍蝇。

我真的觉得使用面向对象的解决方案来解决您的问题是一种极端的矫枉过正。仅仅因为您可以设计面向对象的解决方案,并不意味着您必须对遇到的每个问题都强制使用这样的解决方案。

根据我的经验,几乎每次很难找到解决问题的 OOD 解决方案,这可能意味着 OOD 不合适。OOD 只是一个工具,它本身并不是上帝。它应该用于解决大规模问题,而不是您提出的问题。

所以给你一个实际的答案(正如上面提到的那样):使用正则表达式,除此之外的每个解决方案都只是矫枉过正。

如果您坚持使用 OOD 解决方案......好吧,由于您提供的所有格式都是相互正交的,我认为没有必要为每种可能的组合创建一个类。我将为每种格式创建一个类并通过每个格式传递我的输入,在这种情况下,复杂性将线性增长。

于 2009-06-30T10:35:43.227 回答