我该如何处理行为组合?

时间:2009-06-30 09:42:32

标签: c++ oop software-design procedural-programming

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

实数可能有不同的格式组合,例如: 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语句和标志。

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

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

5 个答案:

答案 0 :(得分:4)

  

在OO设计中,您通常会这样做   为每个号码分配一个类   格式(例如,在这种情况下,我们有8个   类),每个类都有一个   单独的验证功能。

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

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

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:2)

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

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

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

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

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

答案 3 :(得分: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()}
 }

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

答案 4 :(得分:0)

你不要用锤子杀死苍蝇。

我真的觉得为你的问题使用面向对象的解决方案是一种极端的过度杀伤力。仅仅因为您可以设计面向对象的解决方案,并不意味着您必须将此类问题强加给您所遇到的每一个问题。

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

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

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