为什么我看不到使用OOP的真正意义?

时间:2010-12-17 14:26:33

标签: php oop theory

  

可能重复:
  Classes. Whats the point?

我已经阅读了大量的教程,写了许多课程,使用过它们,但我仍然无法弄清楚一些OOP点。

我的意思是,我认为我得到了这个理论。这是一种范式,一种思考和解决问题的不同方式。我知道所有的共同点:代码重用,封装,更好的错误处理,更容易维护,继承,按合同设计,更好的文档,聚合,组合,一些设计模式......

那就是说,让我们去做真正的交易吧。假设我有以下内容:

  • 数据库,以及用于访问和查询它的类。
  • 我有一个名为person的表和另一个名为address
  • 的表
  • 简单的商业规则:一个人可以拥有一个或多个地址(家庭,工作,交付......),简单的一对多关系
  • 我有一个用于通信操作的高级类(CRUD)。每个表都有一个类,它是此类的扩展名。
  • 当然,每个类(人和地址)都有自己的方法:例如,getAddressByLocation或getPersonsByAge。
  • 还有十几个视图和几个表格

这一切都很棒,确实很有用但是...我不能停止思考最简单的情况:列出一些人。是的,因为输出表上的每一行都是在一个类实例上创建的。我无法停止思考在未使用的资源上使用了多少内存和CPU。

清单50人意味着创建50个实例,充满了诸如crud,过滤处理上传,验证规则等资源,当我需要运行查询并只用简单的循环输出结果时。

这让我很困惑。而且不仅仅是混淆,因为我已经看到了一些应用程序,当业务规则稍微复杂时,运行时会随着数据库的增加而呈指数级增长。

我认为,创建新类或普通脚本以处理输出和报告的情况如何?如果是,那么这意味着双重努力,使用OOP毫无意义,一旦我需要为同一个数据库实体创建许多不同的类。编码变得更难,维护也不会变冷。

我错过了什么吗?或者这是OOP方法的缺点?

为了更快地开发和维护,我们是否应该直接牺牲一些简洁,快速的代码?

修改

正如所料,我之前提出的一些观点对某些人来说是误导......

首先,我经历了真正非常大的项目(我曾在IBM为Sprint / Nextel USA和Directv North America工作,因此我习惯于看到每天处理一些太字节)。

当我说从数据库中检索到50个人时,我并不是指50个人,我只想提出许多记录的想法。我知道50条记录对于今天的服务器来说并不算什么。 5000万是。如果合适,想象一下这最后一个数字。

11 个答案:

答案 0 :(得分:9)

正如你所说,这是一种范式。它有任何其他范式的优点和缺点。我认为你错了的地方是什么具有重大意义。是什么让50个实例成为一个大数字?或许对你来说,跟踪50个谨慎的东西是很困难的(对所有人来说都是如此),但这并不意味着它对计算机来说很难。那个50并不大,只因为它对你来说似乎很大。与用于检索数据和整理结果的简单脚本示例相比,这肯定很大,但权衡应该是显而易见的,当您指出OOP的优势时,您列出了大部分内容。更有趣的一点是,当这些优势超过弱点时。判断调用比你在这里确定的更多,包括代码库的大小,涉及的开发人员数量,彼此的相对技能,代码将在生产中保留多长时间等等。

答案 1 :(得分:9)

这是问题的症结所在。如前所述,每个范例都存在权衡。 OOP有很多好处,但是你指出它也有一些负面影响。关键是权衡它们。

OOP建立在开发人员昂贵且硬件便宜的原则之上。它使用此主体来实现高度可维护性(从长远来看易于修复)和高度适应性的代码(从长远来看易于更改)。如果你购买60/60 Rule(表示60%的开发时间在维护中,60%的时间是由于增强),那么可维护性是专业编程的最终目标。

如果你了解OOP是如何工作的(我正在谈论你在OOP范式中的思考点),一切都变得非常简单。我认为你仍然感到困惑,因为你没有完全了解OOP。但话说回来,它也不是编程的圣杯,所以如果你更习惯使用另一种范式,一定要使用它。选择存在是因为我们并非完全相同。使用你最擅长的东西以及你想要做的最好的东西。如果你拥有的唯一工具是锤子,那么每个问题看起来都像钉子......

哦,与流行的观点相反,OOP不是从不编码任何东西。那是DRY(不要重复自己)的校长。虽然它经常与OOP一起使用,但它不是直接附加的。事实上,我建议你在开发时不要遵循DRY作为规则。拍摄它作为一个目标,但让它成为一个规则而不是一个规则。正如弗雷德布鲁克斯所说,计划扔掉一个;无论如何,你会的。(来自The Mythical Man-Month)。如果你绝对不会重复自己,那么当你第一次发现你没有做对的东西的时候,你将会重新做很多工作。只有当它的构建和运行良好时,你应该开始减少它并真正使代码干燥。 (至少个人意见)......

答案 2 :(得分:5)

为您提供一个关于您主要担心的简单示例:

$list = DB::query($query);

foreach ($list as $person)
{
  // $person->name
  // $person->address
  // .. and so on 
}

首先,如果你得到一个点,你是否有每个人的一个类的实例,当你想要一个列表时,那么从一开始就是糟糕的编程,你应该检查自己的OOP知识(尽量不要粗鲁,对不起,如果我是。)

答案 3 :(得分:4)

我担心你缺少的是与大项目长期合作的真实经历。这意味着你有100%的理论概念,但它们是理论上的。当我第一次学习编程功能时(在C中),我想知道为什么我们需要它。但是当我开始编写比以前更大的东西时,我意识到为什么我们需要它们。当我第一次学习OOP时也是如此。为什么我们需要这个?但是如果没有它我现在想不出来。所以我的总结是,尝试在一些真正的大项目中做出贡献。至少在软件开发中,只有理论是不够的。

如果你已经有足够大项目的经验,那么请忽略这个答案。

答案 4 :(得分:2)

如果你看一下DDD,你有一个包含域实体的独立域层;每个都包含属性和域逻辑。另一层是基础架构,其中包含存储库(您的CRUD操作是针对特定资源和技术实现的)。

检索域实体列表由存储库完成,您获得的是50个域实体实例以及所需的域逻辑。您需要此信息,以确保您的客户不会滥用它。

你认为获得50个具有复杂域逻辑的项目会杀死你的系统吗?

答案 5 :(得分:2)

你的框架与范例混淆。

框架是一种结构,您可以在其中编写代码以使维护更容易。在这种情况下,您使用的框架以知道如何出去获取自己的数据的对象为中心。

这是一种简单的方法,正如您所发现的那样,可以导致查询数量呈指数级增长。

更好的方法是创建一个工厂类,返回具有所有地址的人员数组。此工厂对象合并您的请求,并在创建对象之前运行尽可能少的查询,方法是将数据库(或DTO)中的行传递给Person的每个新实例。

请记住,并非所有对象都与现实世界直接相似。人不是在工厂制造,但你真的没有人,是吗?

工厂+代表对象+(可选)数据传输对象是大多数面向对象的大型应用程序中的一个鲁棒且经过验证的框架组件。

但不是全部。还有其他方法可以给这只猫上皮。

OO不是问题所在。你的规则是。您正在使用的框架是。 (自我强加或第三方,没关系)

记住。 OOP绝对不会编码任何两次。框架是为了使代码易于更新,升级和维护而有选择地决定要编码两次的代码。

答案 6 :(得分:1)

你因为“OOP =范式”模因而陷入困境。实际上,对于PHP,它只是一种符号式的风格。当您使用混合语言时,您应该为每个应用程序部分使用最佳方法。程序和对象之间的区别只是API的外观和感觉。

是的,有分组和继承,您可以使用对象结构更好地抽象和概括实用程序代码。但是对于实际行为和功能,您不应该将自己局限于任何一种方法。不是每一个钉子都是面向对象的,并不是每个钉子都是程序性的。这都是关于美化API的。

另外,忘记微观绩效差异。

答案 7 :(得分:0)

创建50个实例并不是什么......在遇到实际问题之前不要担心性能问题。大多数需要花费很长时间才能加载的脚本要么是因为它们执行复杂查询,要么是必须获取远程资源。

关于努力和可维护性问题 - 我想你很快就会发现,正确构建你的程序的初步努力是值得的。例如,如果您随后更改数据库中人员表的列名称,则只需更改一个类,而不是通过应用程序分散的多个查询。

答案 8 :(得分:0)

如果您正在编写一段简短的代码,那么以后要修改它时的开销很小:即使您必须从头开始重写它,也无所谓。随着系统的发展,您必须以更谨慎的方式设计代码:文档接口,提供抽象,封装复杂性,并提供测试系统隔离部分的机制。 OO提供了一组设计思想,让您可以将这些构思构建到代码中。

困难在于了解简单代码之间的差异,这些代码将变得更大和更复杂(在这种情况下,您可能希望从OO设计开始),并且当您拥有永远不会改变的简单代码时(在在哪种情况下你想做最简单的事情,而不是支付全部OO的开销。在这两者之间挑选真的很难,尽管我倾向于假设代码会增长,因为过度设计的小代码与仅在其初始设计之外发展的代码不足的代码相比只是中度差。

答案 9 :(得分:0)

OOP是通过应用各种概念来解决问题的方法。这些概念可以以严格的OO方式一起使用,也可以与其他范例中的其他概念混合使用。大多数现代编程语言不再仅仅是一种范式或另一种范式。它们通常包含来自这些范例的其他范例和/或概念。例如,“延迟评估”,来自函数编程的概念可以与OO概念一起使用,以创建被懒惰评估的对象列表。或者你可以简单地使用一个惰性列表来构建对象。

FYI您的共同点,其中许多都与其他范例共享。

答案 10 :(得分:0)

不要忘记测试!

使用您使用的实体对象允许您执行依赖项注入,并在应用程序的每个级别独立提供测试和调试。对于喜欢密码化的开发人员来说,这是一个巨大的福音。

如果您使用像.Net这样的结构,像MVP这样的结构,尤其如此,因为通过分离对象,您真正确定了图层和代码可重用性的冲突。