12

这出现在我在网上进行的一次谈话中,我突然想到我不知道这应该如何工作:相当多的程序员似乎只是把它当作一个给定的——事实上,很明显,类是一种必要的语言用于管理大型软件项目的功能。

他们如何做到这一点对我来说并不明显。

我的问题是,你怎么知道?有哪些客观措施表明类可以提高生产力、代码重用并降低程序生产的复杂性?类的哪些方面使它们成为大型团队协作的理想选择?

现在,我想问一个问题,这有点难以表达。如果我弄错了并最终使任何人感到困惑或激怒,我很抱歉:

客观地说,你怎么知道类的使用不是导致应用程序变大的原因呢?也就是说,是否可以使用其他代码重用策略编写具有等效功能的程序,代码少得多,小到不需要任何特殊措施来“管理”它?(有很多可供选择,例如函数式编程范例或面向方面的编程)。

最后一点是史蒂夫·耶格(Steve Yegge)在他的博客上暗示的。但我对争论的双方都持怀疑态度,因为真正缺乏任何人的任何硬数据,也没有足够的经验来独自得出结论。

你怎么看?

编辑:我特别感兴趣的是为什么许多程序员认为原型样式继承在大型应用程序中不能胜任这项任务。我很抱歉这个问题含糊不清 - 这是我对这个话题缺乏了解的产物。

编辑2:我所说的函数式编程似乎有些混乱。(我认为任何版本的 VB 都没有功能,当然不是旧版本)。请参阅维基百科文章。 http://en.wikipedia.org/wiki/Functional_programming

编辑3:让我强调我正在寻找客观的措施。不是主观意见。

4

11 回答 11

6

这个问题问得好。将代码组织成类是开发团队创建小型、可重用模块的一种方式。此外,这些模块具有表达性和有限的接口,只表达类的能力,而不是它是如何做到的。每个类都与其他类正交,因此在出现错误时具有高度的可测试性和模块化。

现在我刚才描述的是一个完美世界的奇异景象。但是任何从事 OOP 工作的优秀开发人员都应该为这样的事情而努力。

OOP 承认我们,开发人员,只是人类,不能立即理解整个系统。因此,我们将系统分解为可重复使用的微小部分并专注于这些部分。

以一个十位数的美国电话号码为例。在你的头脑中记住一个十位数是很困难的,所以我们做了心理学家所说的“分块”。这意味着我们在精神上将数字分解成我们可以更好地记住的块。

就这样1234567890变成了123-456-7890。对我们来说幸运的是,电话公司也以同样的方式将这些数字分解并分配块的含义。 123是区号,456是前缀,7890是行号。这些块中的每一个都像一个类,它们都有各自的职责、格式和含义。

所以总而言之,我能说的最好的事情是 OOP 允许我们构建具有集中和封装功能的大型、可扩展系统。它使我们不必一直看大局,而能够专注于做一件事并把它做好。

于 2009-01-19T01:12:05.137 回答
2

我绝不是对任何编程范式的偏执狂,但我已经以 OO 方式操作了一段时间。

就个人而言,我有很多'a-HA!课程直接帮助我更好地理解我正在工作的领域的时刻。

最值得注意的是,如果对系统故障的原因或系统应该做什么感到困惑,课堂经常迫使我思考这个离散的整体应该做什么,而且往往不是领导重构手头的类/方法。

总之,封装真的让我成为一个更快乐的人。;)

希望有帮助。

于 2009-01-19T00:35:17.300 回答
2

我认为类可以提供帮助,因为它们对应于非常普遍的分类认知概念,因此可以帮助自然地描述大型应用程序。

于 2009-01-19T01:23:05.863 回答
2

封装理论提供了一个客观原因,为什么类比没有类更好。

国际标准化组织将封装定义为“对象中包含的信息只能通过对象支持的接口上的交互来访问的特性”。

因此,由于某些信息可通过这些接口访问,因此某些信息必须在对象内隐藏且不可访问。此类信息表现出的属性称为信息隐藏,Parnas 通过认为模块应该被设计为隐藏困难的决策和可能改变的决策来定义。

注意那个词:改变。信息隐藏涉及潜在事件,例如未来困难设计决策的变化。

考虑一个具有两种方法的类:方法 a() 是隐藏在类中的信息,方法 b() 是公共的,因此其他类可以直接访问。

将来对方法 a() 的更改很有可能需要更改其他类中的方法。未来对方法 b() 的更改也有一定的可能性需要更改其他类中的方法。然而,方法 a() 发生这种波动变化的概率通常低于方法 b() 的概率,这仅仅是因为方法 b() 可能会被更多类所依赖。

这种减少涟漪影响的可能性是封装的一个关键好处。

考虑任何程序中源代码依赖项(MPE - 首字母缩写词来自图论)的最大潜在数量。从上面的定义推断,我们可以说,给定两个向用户提供相同功能的程序,MPE 最低的程序封装得更好,并且从统计上来说,封装得更好的程序维护和开发成本更低,因为成本它的最大潜在变化将低于封装不太好的系统的最大潜在变化。

此外,考虑一种只有方法而没有类的语言,因此没有相互隐藏信息的方法。假设我们的程序有 1000 个方法。这个程序的 MPE 是多少?

封装理论告诉我们,给定一个有 n 个公共节点的系统,这个系统的 MPE 为 n(n-1)。因此,我们的 1000 个公共方法的 MPE 为 999,000。

现在让我们将该系统分成两个类,每个类有 500 个方法。由于我们现在有类,我们可以选择将一些方法设为公共的,而将一些方法设为私有的。除非每种方法实际上都依赖于其他所有方法(这不太可能),否则情况就是如此。假设每个类中有 50 个方法是公共的。系统的 MPE 是多少?

封装理论告诉我们它是:n((n/r) -1 + (r-1)p) 其中 r 是类的数量,p 是每个类的公共方法的数量。这将使我们的二分类系统的 MPE 为 499,000。因此,在这种二类系统中进行更改的最大潜在成本已经大大低于未封装系统的最大潜在成本。

假设您将您的系统分成 3 个类,每个类有 333 个类(好吧,一个将有 334 个),并且每个类都有 50 个公共方法。什么是 MPE?再次使用上述等式,MPE 约为 482,000。

如果将系统分成 4 类,每类 250 个方法,则 MPE 将为 449,000。

如果看起来增加我们系统中的类数量总是会降低它的 MPE,但事实并非如此。封装理论表明,为了最小化 MPE,系统应该分解成的类数是: r = sqrt(n/p),对于我们的系统,实际上是 4。例如,具有 6 个类的系统将具有 MPE 465,666。

于 2009-01-26T18:34:41.727 回答
1

我更喜欢类,以便我可以将一个大问题分成可作为单独单元进行测试的可管理部分。恕我直言,代码重用被高估了——我几乎没有看到它发生在我工作的地方。对我来说,我从好的 OO 中得到的最大好处是良好的可测试性。

另一个极端是使用一堆全局变量,把你所有的逻辑都塞进public static void main(或Page_Load在ASP.NET中),然后调用调用其他静态方法的静态方法等等……(我在最后一句话的结尾头晕了) .)

唯一会打破我的 OO 思维方式的是,如果我使用的是纯函数式语言,不幸的是,这是我自大学以来就没有考虑过的事情。

于 2009-01-19T01:11:28.117 回答
1

通过使简单的问题变得不必要的复杂(一直到OO),可能会过度设计一个简单的问题。但是,对于任何足够大的问题,我认为 OO 范式不太可能是导致它首先变大的原因。以操作系统为例,如果它不是以面向对象的方式编写的,很难想象它易于维护(代码方面)。

于 2009-01-19T02:31:50.997 回答
1

如果您在大型应用程序中有一堆“裸”功能,则很难对这些功能进行更改。

  • 更难看出谁在使用该功能(“如果我改变它,它会影响谁?”)
  • 很难在不破坏其他人代码的情况下对功能进行更改。

如果将函数包装在类中,则有助于隔离代码的范围。这不是灵丹妙药,但它有帮助。

于 2009-01-19T02:34:55.983 回答
0

两件事情。

第一个是类是不透明的域实体的想法。如果做得正确,面向对象的程序会引入一个抽象层:在下一个最高层,您可以将对象编组为您想做的事情,而不是处理细节。您不需要知道对象和类是如何工作的:只需要知道它们的作用。这是一种信息隐藏,它降低了团队在工作时必须记住的复杂性。

第二个是OO编程允许一种代码重用:您可以定义覆盖其他类中某些行为的类(继承),或者其实例包含其他类实例的类,使用它们来实现其目的(封装和组合) .

正确使用 OO 技术可以减少您需要管理的代码量,并减少您在工作或维护系统时需要记住的事情的数量。在实践中,这种方法并不总是有效。

于 2009-01-19T01:18:52.987 回答
0

客观地说,你怎么知道类的使用不是导致应用程序变大的原因呢?

以任何不是用 OO 语言(例如 C、COBOL,甚至是普通 SQL)编写的大型程序/应用程序为例,您应该能够看到代码大小并不直接归因于语言范式。对于每一个设计良好、高度精炼、可重用的 C# 或 Java 组件,也有相同数量的精心设计、高度精炼、可重用的 C DLL。相反,有同样数量的可怕、臃肿的代码。

关键是,优秀的程序员能够改进他们的系统设计,而不管语言/平台如何。

关于 OOP,至少对我而言,它带来了一种“潜力”——一种更接近我们现实世界的编程世界观。我们都知道我们的世界和这个物质宇宙充满了由更小的物体组成的物体。从银河系的恒星系统一直放大到分子、原子和亚原子粒子,令人惊叹的是,由相同的微小粒子以各种模式组合而成的截然不同的物质是多么的惊人。甚至看看我们自己的生物学,有时认为我们身体的 60% 被分解到最好的状态实际上只是水,这令人难以置信。然而,看看所有不同的系统和器官都在燃烧着化学物质,让我们保持运转和活着。

当我们学会理解构成我们在日常生活中看到的现实世界系统的构建块的简单性(哦,真的......哈哈),我们应该能够理解设计和构建极其复杂或复杂的系统应该从自己做的很少的小组件开始。通过慢慢地将它们组合和网格化成更大的组件,我们可以获得更多的功能和能力。直到我们达到我们设想的所需系统。

(正确)使用类是将系统分解成最好的。尽可能。这样您就可以一次查看某些内容和特定的抽象级别,而不会被与您当前关注的领域无关的目的和逻辑所淹没。每当你设计一个系统时,想想你自己的解剖结构;想想你将如何设计人体。每当您设计系统时,请考虑创办一家新公司;什么是主要部门,您需要经营业务的部门。谁是管理这些部门所需的员工类型。他们需要使用并与之交互以执行工作的各种设备。您如何将业务运营分解为最精细的部分,以便让自己更好地理解它?

当您了解某些物体只是由较小的物体组成的基本原理时,您将开始创建高度可重复使用的细胞或分子。

于 2009-01-19T02:03:56.110 回答
0

在我可以一次处理复杂项目的一小部分方面,课程对我最有帮助。能够将代码的一个方面与大型项目分离是非常有帮助的,这样您就不会不知所措。最后,这些类之间的凝聚力可以​​让您快速了解程序的工作原理,而无需处理内部问题。

就可维护性而言,在我看来,查看 UML 类图并弄清楚所有内容的布局比查看函数列表要容易得多。

于 2009-01-19T02:05:50.473 回答
0

我认为通过说类,你应该指对象。类只不过是您可以放入对象的地方。OOP 范式如此成功是有原因的。一旦你有那个'啊哈!当您认为您终于理解了 OOP 的概念时,您可以开始以更有条理的方式进行编程。

我已经在 Visual Basic 3 中编程了很长时间,所以我在函数式编程方面有很多经验,然后来到 VB5 并发现对象是一种巨大的解脱,因为我可以将现实世界的实体与我的代码联系起来,它帮助很多。

这就是它的全部意义,在您的代码中重新创建真实世界的实体。它使阅读和工作更容易,因为您可以拿起一些东西并用它做一些事情,或者对它做一些事情。

于 2009-01-19T02:29:40.830 回答