多少抽象太多了?

时间:2010-04-19 14:47:30

标签: language-agnostic oop abstraction

在面向对象的程序中:抽象多少太多了?多少钱是对的?

我一直是个蠢货。我理解高级封装和抽象背后的概念,但总觉得添加太多会让程序混淆。

我总是试图拍摄一些没有空类或层的抽象。如果有疑问,我会尝试在现有图层中添加一些新图层,而不是在层次结构中添加新图层。

然而,最近我遇到了更多高度抽象的系统。系统中可能需要在层次结构中稍后表示的所有内容都可以预先获得。这导致了很多空层,起初看起来像是糟糕的设计。然而,第二个想法我已经意识到,留下那些空白的层将为你提供更多的地方可以在未来进行重构。它使您能够更好地在旧版本之上添加新功能,而无需进行相当多的工作来调整旧功能。

这样做的两个风险似乎是你可以得到你需要错误的图层。在这种情况下,人们最终还是需要进行大量的重构来扩展代码,并且仍然会有大量未使用的层。但是,根据您花费多少时间进行初始抽象,将其搞砸的可能性,以及如果您做得正确可以节省的时间 - 可能仍然值得尝试。

我能想到的另一个风险是过度做的风险,从不需要所有额外的层。但那真的很糟糕吗?额外的类层真的如此昂贵,如果从未使用它们会有很大的损失吗?这里最大的费用和损失将是前面提到的层丢失的时间。但是,当人们可以使用抽象代码而不是更低级别的代码时,大部分时间仍然可以保存。

那么什么时候太多了?空白层和额外的“可能需要”抽象在什么时候变得有点过分?太少了?哪里是最佳点?

您在职业生涯中是否有任何可靠的经验法则可以帮助您判断所需的抽象量?

8 个答案:

答案 0 :(得分:30)

抽象的要点是分解来自特定属性的常见属性,如数学运算:

ab + ac => a(b + c)

现在你用两个操作而不是三个操作做同样的事情。这种因素使我们的表达更简单。

抽象的典型示例是文件系统。例如,您希望程序能够写入多种存储设备:笔式驱动器,SD卡,硬盘驱动器等......

如果我们没有文件系统,我们需要实现直接磁盘写入逻辑,笔式驱动器写入逻辑和SD卡写入逻辑。但所有这些逻辑都有一些共同之处:它们创建文件和目录,因此可以通过创建抽象层,并为硬件供应商提供接口来完成特定的事情,从而抽象出这些常见的东西。

事物共享共同财产的次数越多。抽象可能更有益:

ab + ac + ad + ae + af

为:

a(b + c + d + e + f)

这会将9次操作减少到5次。

基本上每个好的抽象大致将系统的复杂性减半。

您总是需要至少两个共享公共属性的东西才能使抽象变得有用。当然,你撕开一个东西,所以它看起来像一个抽象,但它并不意味着它是有用的:

10 => 5 * 2

如果您只有一个实体,则无法定义“common”这个词。

所以回答你的问题。 如果您的系统尽可能简单,那么您有足够的抽象。

(在我的例子中,加法连接系统的各个部分,而乘法定义了抽象 - 具体的关系。)

答案 1 :(得分:25)

  

有多少太少了?

当你在日常工作中继续使用“低级”元素时,你总是觉得你不想这样做。摘要'离开。

  

那么什么时候太多了?

当你不能定期制作一些代码部分的零碎时,必须将它们调试到前一层。你觉得这个特定的层没有贡献任何东西,只是一个障碍。放弃它。

  

哪里是最佳点?

我喜欢运用务实的方法。如果您认为需要抽象并了解它将如何改善您的生活,那就去做吧。如果你听说应该“正式”一个额外的抽象层,但你不清楚为什么,不要做,但先研究。如果有人坚持抽象某些东西但却无法清楚地解释将会带来什么,请告诉他们离开。

答案 2 :(得分:21)

  

那么什么时候太多了?在什么时候   做空的层和额外的“可能   需要“抽象变得矫枉过正吗?   太少了?在哪儿   甜蜜点?

我认为这些问题没有明确的答案。需要经验来培养“太多”和“太少”的感觉。也许使用某些指标或质量控制工具可能有所帮助,但很难概括。这主要取决于每个案例。

以下是一些可能会激发您寻求答案的链接:

开发就是在任何软件工程工作中出现的各种紧张关系之间找到适当的平衡。

答案 3 :(得分:9)

从理论上讲,应该只使用三个(相当简单的)变量来进行简单的数学运算:

  • S =使用节省
  • C =额外抽象的成本
  • P =使用概率

如果S * P> C,那么代码很好。如果S * P < C,那就太糟糕了。

然而,纯粹理论上的原因是,您通常无法猜测使用概率或使用它所带来的节省。更糟糕的是,你无法猜测或者甚至通常衡量其存在的成本。

至少有些人从中得出结论。在TDD中,标准的口号是“你不需要它”(YAGNI)。简而言之,任何不直接有助于满足当前要求的代码都被认为是一件坏事。从本质上讲,他们已经得出结论,使用概率非常低,包括这样的额外代码永远不会合理。

其中一些回归到“自下而上”与“自上而下”的发展。我倾向于将自下而上的发展视为“图书馆发展” - 即。而不是开发一个特定的应用程序,你真的开发了应用程序中你需要的东西的库。我们的想法是,通过一个足够好的库,您可以相对容易地开发几乎所有类型的应用程序。

还有一点还取决于项目的规模。几十年来一直使用的巨大项目证明了比小型项目更长期投资更多,这些项目被丢弃并且更快地被替换。这在现实生活中也有明显的类比。您不必担心一次性剃须刀的合身性,光洁度或工艺性,您将在不到一周的时间内扔掉,就像您将在未来几年内使用的新车一样

答案 4 :(得分:6)

简单地说,如果代码难以理解,那么抽象太多了。

现在这并不是说您应该对所有内容进行硬编码,因为这是最容易编写和读取的代码。

最简单的测试是要么把它放下几天,然后再回头问问自己,这是否有意义。更好的方法是将其交给其他人,看看他们是否可以做出正面或反面。

答案 5 :(得分:2)

现实情况是,这取决于你对未来的看法。您希望计划可以预见的更改,而无需创建太多额外的图层。如果您的设计在系统之间传输数据,请继续创建接口并使用计划的实现作为默认设置。例如,您使用FTP移动文件,但明年标准将基于消息(或其他)。

对于设计中的图层,有时添加的图层可以更轻松地编写较小的类。如果它意味着具体的类变得简单,那么添加概念层是可以的。

答案 6 :(得分:1)

实际上没有使用的每个抽象都太多了。系统越简单,就越容易改变。抽象层几乎总是使系统更复杂。

OTOH,当然有可能在没有任何抽象的情况下编写复杂的,无法维护的混乱,有时,“标准化”抽象层可以帮助构建一个比大多数人自己能够做的更好的系统。

答案 7 :(得分:0)

参见RFC 1925(6a)项,并知道确实如此。通过添加抽象层无法解决的唯一问题是由于抽象层太多而导致的问题。 (特别是,每一个抽象都使整个事情更难理解。)