【问题标题】:Why I can't see a real point for using OOP? [duplicate]为什么我看不到使用 OOP 的真正意义? [复制]
【发布时间】:2010-12-17 14:26:33
【问题描述】:

可能重复:
Classes. Whats the point?

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

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

也就是说,让我们开始真正的交易吧。假设我有以下内容:

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

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

列出 50 个人意味着创建 50 个实例,充满资源,如 crud、过滤处理上传、验证规则等,而我需要的是运行查询并通过简单的循环输出结果。

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

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

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

我们是否应该牺牲直截了当、精简、速度更快的代码来获得更快的开发和维护?

编辑

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

首先,我非常擅长大型项目(我曾在 IBM 供应商为 Sprint/Nextel USA 和 Directv North America 工作,所以我习惯于看到每天处理一些 TB 的数据)。

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

【问题讨论】:

  • Listing 50 people means creating 50 instances - 没必要。在可维护代码方面,OOP 是大炸弹。无论如何,这是一个很好的问题,但可能更适合新的programmers.stackexchange.com(我认为这里有类似的问题)
  • 没有OOP我活不下去!此外,您的陈述应该回答您的问题,因为您似乎不了解 OOP 是什么以及如何使用它:)
  • 为什么需要制作 50 个实例?创建一个接受连接和查询并返回所需输出的 ​​PeopleLister 类。
  • @nos - 重点不在于编码本身,而在于运行时和语言内部。据我了解,当您创建一个类并实例化它时,所有属性和方法都在内存中可用。当您不需要它们时,为什么有大量可用的方法?那是我的问题。
  • @Dave 与对象,方法不会被复制,每个对象实例化都会重复使用一组方法,通常只有属性是每个对象的。

标签: php oop theory


【解决方案1】:

这是问题的症结所在。如前所述,每种范式都需要权衡取舍。 OOP 有很多好处,但正如您所指出的,它也有一些负面影响。关键是权衡它们。

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

如果您了解 OOP 的工作原理(我说的是您在 OOP 范式中的思考点),那么一切都会变得非常容易。我认为您仍然感到困惑,因为您没有完全了解 OOP。但话又说回来,它也不是编程的圣杯,所以如果您更习惯使用另一种范式,请务必使用它。存在选择是因为我们并不完全相同。使用你最擅长的和最适合你最擅长的。如果你唯一的工具是锤子,那么每个问题看起来都像钉子......

哦,与流行的观点相反,OOP 并不是关于从不编码任何东西。这就是 DRY(不要重复自己)原则。虽然它经常与 OOP 一起使用,但它并不直接附加到。事实上,我建议在开发时不要遵循 DRY 作为规则。将它作为一个目标而努力,但让它成为一个指导而不是规则。正如 Fred Brooks 所说,打算扔掉一个;无论如何,你会的。(来自The Mythical Man-Month)。如果你严格地从不重复自己,那么当你需要扔掉一些你第一次没有做对的东西时,你最终会重新做很多工作。只有当它构建并运行良好时,您才应该开始精简它并真正使代码干燥。 (至少个人意见)...

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      为您提供一个简单的示例,说明您主要关心的问题:

      $list = DB::query($query);
      
      foreach ($list as $person)
      {
        // $person->name
        // $person->address
        // .. and so on 
      }
      

      首先,如果您有一个点是每个人都有一个类的实例,当您想要一个它们的列表时,那么从一开始就是糟糕的编程,您应该回顾自己的 OOP 知识(尽量不要粗鲁,对不起)。

      【讨论】:

      • 嗯?我不确定你在这里说什么。每个人只有一个实例很糟糕吗?不是我同意,但是为什么你有$person->name等?
      • @Artefacto,$person 不一定是真实的对象(在 OOP 世界中)。例如,您可以通过 $person = new stdClass 创建一个对象,这将让您作为对象执行操作,而无需声明任何方法。
      • 我希望有人提及“使用 stdObject”。然而,我的主张更多是从设计的角度来看。您的回答和评论说明了问题,但并没有真正回答。
      • @Dave,一个好的软件不一定是完美的(甚至不存在,或者太复杂),但它必须在他的主要领域非常非常好,至这就是 DDD 的意思。再一次,我可以与任何你想要的聊天客户端讨论这个问题,这是一个非常好的主题,但也很长。
      • 我现在需要离开,但稍后我们可以聊聊。我很感兴趣。
      【解决方案4】:

      恐怕您缺少的是长期从事大型项目的真实经验。这意味着你有 100% 的理论概念,但它们是理论的。当我第一次学习编程函数(用 C 语言)时,我想知道为什么我们需要这个。但是当我开始编写比以前更大的东西时,我意识到我们为什么需要它们。当我第一次学习 OOP 时也会发生同样的情况。为什么我们需要这个?但现在没有它我不能想太多。所以我的总结是,尝试为一些真正的大项目做出贡献。至少在软件开发中,只有理论是不够的。

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

      【讨论】:

      • 没错。通过贡献或参与一些大型集体项目(不是快速网站或博客),您将学会欣赏 OOP 的好处。
      【解决方案5】:

      您将框架与范式混淆了。

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

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

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

      请记住,并非所有对象都直接模拟现实世界。人不是在工厂里制造出来的,但你那里真的没有人,对吗?

      工厂 + 代表对象 +(可选)数据传输对象是大多数面向对象的大型应用程序中可靠且久经考验的框架组件。

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

      OO 不是这里的问题。你的规则是。您正在使用的框架是。 (自己强加还是第三者,没关系)

      记住。 OOP 是关于从不编码任何东西两次。框架是关于有选择地决定对什么进行两次编码,以使代码易于更新、升级和维护。

      【讨论】:

      • 我的问题不是专门针对框架,也不是设计模式。但是指出一个好的设计(或设计模式会有所帮助)。也是 OOP 内部。
      【解决方案6】:

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

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

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

      【讨论】:

      • 请检查我的编辑。我要求的不是 MVC,而是整个设计,我的意思不是字面上的 50。如果你愿意,可以用一个非常高的数字替换(100 亿会很好)。
      • 我没有回复 MVC。我认为您可能需要先了解架构和设计模式。如果你想检索 500 亿条记录,还有其他一些大错特错的地方。
      • 您的输入还不错。实际上,它们几乎对我有好处,只是它们进入了与我希望该线程完全不同的方向。没关系,谢谢分享。
      • 我能说什么...我爱 DDD ;)
      【解决方案7】:

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

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

      另外,忘记微观性能差异。

      【讨论】:

        【解决方案8】:

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

        至于工作量和可维护性问题——我想您很快就会发现,正确构建程序的最初努力是值得的。例如,如果您随后更改人员表的数据库中列的名称,您只需要更改一个类,而不是在应用程序中展开的多个查询。

        【讨论】:

        • @Dave PHP的应用领域本质上是网页。您永远不会在一个网页中处理 5000 万个对象。如果你是,那么就发生了一些非常错误的事情,因为 Web 客户端将永远等待。您可以在数据库中的一个表中拥有 5000 万条记录,但您通常会在网页中显示最多 200 个条目,这就是您需要在内存中拥有的内容,甚至可能不会同时存在。
        • 老兄,你误会了。真的错了。但没关系......这种事情发生了。
        • 该问题并非特定于数据库查询,也不是真正要检索的 50 个对象或 5000 万行。问题是关于在不需要 OOP 的情况下分配许多资源(在类中编写的方法)。我知道 50 条记录不算什么,也知道用一个查询检索 5000 万条记录只是疯狂和糟糕的设计。但是想想当你有一个共享主机时(大多数 php 托管服务都是共享的)......由于这种开销,你可以分配 200 个项目而不是 20 个项目......这或多或少是我想要表达的意思......
        【解决方案9】:

        如果您正在编写一小段简单的代码,那么以后想要修改它的开销很小:即使您必须从头开始重写它,也没有关系。随着系统的发展,您必须以更加谨慎的方式设计代码:记录接口、提供抽象、封装复杂性并提供测试系统隔离部分的机制。 OO 提供了一套设计理念,让您可以将它们构建到您的代码中。

        难点在于了解将变得更大更复杂的简单代码(在这种情况下,您可能希望从 OO 设计开始)与您拥有永远不会改变的简单代码(在在这种情况下,您希望做最简单的事情,而不是支付完全 OO 的开销)。确实很难在这两者之间做出选择,尽管我倾向于假设代码会增长,因为与超出其初始设计的设计不足的代码相比,过度设计的一小段代码只是中等程度的糟糕。

        【讨论】:

          【解决方案10】:

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

          仅供参考,您的共同点,其中许多在其他范例中是共享的。

          【讨论】:

          • +1 我喜欢你的意见,特别是提到惰性评估。我从功能范式中知道这一点,但大多数人认为这是一种 OOP 独有的模式。
          【解决方案11】:

          别忘了测试!

          拥有与您一起工作的实体对象允许您进行依赖注入,并在应用程序的每个级别独立地提供测试和调试。这对于喜欢让代码密不透风的开发人员来说是一个巨大的福音。

          如果您使用 .Net 之类的语言和 MVP 之类的结构,则尤其如此,因为通过分离对象,您可以真正确定层级和代码可重用性。

          【讨论】:

          • 是的,只要可行,测试总是在范围内。
          猜你喜欢
          • 2023-03-23
          • 2011-03-15
          • 2020-05-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多