【发布时间】:2008-09-25 19:42:52
【问题描述】:
我是一名 PHPer,并且不编写面向对象的代码。
OO 与过程代码相比有哪些优势,我在哪里可以学习如何将这些想法应用到 PHP 中?
【问题讨论】:
我是一名 PHPer,并且不编写面向对象的代码。
OO 与过程代码相比有哪些优势,我在哪里可以学习如何将这些想法应用到 PHP 中?
【问题讨论】:
它不会自动帮助您。您可以编写比结构化程序更糟糕的“OO”程序,反之亦然。 OOP 是一种工具,可让您创建更强大的抽象。
【讨论】:
对象有助于使您的代码在不同部分之间保持隔离,因此如果您需要对一个部分进行更改,您可以确信它不会影响其他部分:松散耦合。
然后,当您这样做一段时间后,您会开始发现您为一个应用创建的对象在其他应用中也很有用,并且您也开始获得更好的代码重用。因此,新应用已经完成了部分工作,并且使用了经过时间考验的代码:软件构建速度更快,错误更少。
【讨论】:
人们会从不同的角度告诉你关于 OOP 的各种事情。但是如果你想形成自己的观点,而不是接受别人的观点,那么我建议阅读 Bertrand Meyer 的“面向对象的软件构建”。
本质上,他采用了非 OOP 编程技术,并分析了它们的基本缺陷。然后,他推导出了一种替代技术来解决这些缺陷。换句话说,他从第一原则推导出 OOP。这是一部了不起的作品,非常令人信服。
阅读它,您会以一种可以推理支持的方式了解原因、时间和内容。
【讨论】:
对象有助于封装复杂性。对于大多数 PHP 编程,不可能为任何相当复杂的应用程序编写好的、干净的代码。编写 OO PHP 可帮助您将代码放入自己的盒子中,将其与其他所有内容隔离开来。这有几个好处。
Poll::Display()) 上编写一行代码即可实现全部该应用程序可以做什么 - 这让我的主页维护变得更加容易。请记住一件事 - PHP(甚至 PHP5)中的 OO 与 Python 或 Ruby 等语言相比并不是很好的 OO。 Python 中的一切皆为对象的模型让我对 OO 编程非常感兴趣——作为一名前 PHP 程序员(和双重认证的 Zend 工程师),如果你想了解什么是 OO,我强烈建议你探索 Python 的 OO是所有关于。至少它会帮助你编写更好的 PHP 代码。
【讨论】:
是的,如果你真的明白的话。
它可以帮助您直观地了解大型系统的各个部分如何相互交互。它在设计层面非常有用。
如果您只是编写几行代码,您将获得的唯一好处是使用分解为精心设计的对象的库通常比仅使用函数更容易一些。
要充分利用它,您还需要遵循健全的 OO 设计实践。始终封装所有数据,使用许多小类,而不是大的“包罗万象”类。让班级为你做你的工作,而不是向它索取数据并在课堂外做工作等。
它可能暂时不会对您有太大帮助,如果您总是在做小型网站(我不能肯定地说,我不真正做 php),可能永远不会,但随着时间的推移和大型网站项目可能是无价的。
【讨论】:
没有人提到的一件事是OO代码有助于编写可读的代码:
sherry.changePhoneNumber();
phoneCompany.assignNewPhoneNumberTo(sherry);
sherry.receive(new PhoneNumber().withAreaCode("555").withNumber("194-2677"));
我从这种美学中得到了strange satisfaction。
【讨论】:
对我来说最大的胜利是继承,或者使一个对象的行为几乎与另一个对象完全一样,但有一些不同。这是我办公室的一个真实示例:
我们需要代码来处理客户发送给我们的 TIFF 文件,将它们转换为标准格式,将有关文件的一些信息插入数据库,然后发送结果电子邮件。我在一组类中编写了这个(在 Python 中,但想法是一样的)。 “fetcher”类从 POP3 邮箱中获取电子邮件并将它们交给一个“container”类,该类知道如何从电子邮件中读取附件。该类将每个图像传递给执行必要处理的“文件对象”类。
好吧,有一天我们遇到了一位客户,他想发送 PDF 文件。我对“TIFF 文件对象”类进行了子类化,并重写了“规范化”函数以将 PDF 作为输入,但其他所有代码都保持不变。第一次成功了,我很高兴。
更改我们的邮件服务器意味着我需要通过 IMAP 获取电子邮件。再次,我将“POP3 fetcher”子类化,以便它可以使用 IMAP。问题解决了。
另一个客户想给我们邮寄 CD,所以我用“文件系统目录”类子类化了“电子邮件容器”类。瞧 - 完成了。
在每种情况下,新代码都与旧代码有 95% 的相似性。例如,“TIFF 文件对象”类有大约 15 个方法。 “PDF 文件对象”类恰好定义了一个:将特定格式的文件转换为我们的标准的方法。它从其父类获得的所有其他内容。
现在,你绝对可以在程序上做同样的事情,比如写:
if fileobjecttype == 'TIFF':
data = <snip 30 lines of code to read and convert a TIFF file>
elif fileobjecttype == 'PDF':
data = <another 45 lines to read a PDF>
elif fileobjecttype == 'PNG':
data = <yep, another one>
最大的不同是我相信你可以让 OOP 看起来更干净、更有条理。我的 PDF 类看起来像:
class PDFReader(GenericImageReader):
def normalize(self):
data = <45 lines to read a PDF>
就是这样。你一眼就能看出它只做一件不同于它所继承的类的事情。它还迫使你——或者至少强烈鼓励你——在应用程序的各层之间建立干净的接口。在我的示例中,PDFReader 不知道也不关心它的图像是来自 POP3 邮箱还是来自 CD-ROM。 POP3 fetcher 对附件一无所知,因为它的工作只是获取电子邮件并传递它们。在实践中,这使我们能够以绝对最少的编码或重新设计量做一些非常了不起的事情。
OOP 并不神奇,但它是一种让您的代码井井有条的绝妙方法。即使你不到处使用它,它仍然是你真正应该发展的技能。
【讨论】:
有一段时间,当我第一次开始编程时,我编写了面向用户的代码。它工作得很好,但很难维护。
然后,我学习了 OO,我编写的代码变得更易于维护,更易于在项目之间共享,生活也很美好……除了我的用户之外的所有人。
现在,我知道了计算机编程的真正灵丹妙药。我编写 OO 代码,但首先我对象化我的用户。将人视为对象一开始可能看起来很粗鲁,但它让一切都变得更加优雅 - 您可以编写所有软件以使用明确定义的界面,并且当用户发送意外消息时只能忽略它,或者,如果标有表示足够重要性的标志,则向它们抛出异常。
有 OO 的生活是美好的......
【讨论】:
我认为 OOP 适合那些在“对象”中思考的人,其中对象由数据以及对这些数据进行操作的函数组成。
我建议不要出去学习模式。为了做好面向对象的编程,您需要自学像面向对象的程序员一样思考。您需要达到您理解并能说出以下好处的程度:
它只会帮助你成为一个更好的程序员,因为程序员知道的编程风格越多,他解决问题和编写优雅代码的能力就越广。你不可能把所有的代码都写成面向对象并自动拥有好的代码,但是如果你真的了解 OOP 是如何工作的,而且你不只是复制粘贴当时流行的一些设计模式,那么你可以写一些漂亮的好的代码,尤其是在编写大型应用程序时。
【讨论】:
似乎每个人都从字面上回答您的问题,即 OO 的具体好处/缺点。
你应该学习 OO,但不是因为 OO 有你需要的任何特定魔法。
更一般的形式是:
【讨论】:
我会这样说:如果您编写任何复杂的东西,您应该对您思考的概念进行编码,而不是试图以某种方式与您使用的语言原生的概念进行思考。这样可以减少错误。这些概念的形式化称为设计。
函数式编程允许您定义与动词相关的概念,因为每个函数本质上都是一个动词(例如 print())。另一方面,OO 编程还允许您定义与名词相关的概念。
【讨论】:
稍微详细说明乔里的回答:
国际标准化组织将封装定义为“对象中包含的信息只能通过对象支持的接口上的交互来访问的属性。”
因此,由于某些信息可以通过这些接口访问,因此某些信息必须在对象中隐藏且不可访问。此类信息所表现出的特性称为信息隐藏,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 个。
负担原则有两种形式。
强形式表明,转换实体集合的负担是转换实体数量的函数。弱形式表明,转换实体集合的最大潜在负担是转换实体的最大潜在数量的函数。
更详细地说,创建或修改任何软件系统的负担是创建或修改的程序单元数量的函数。
依赖于特定修改程序单元的程序单元比不依赖于修改后程序单元的程序单元更容易受到影响。
修改后的程序单元可能施加的最大潜在负担是对依赖它的所有程序单元的影响。
因此,减少对修改后的程序单元的依赖性会降低其更新影响其他程序单元的可能性,从而减少该程序单元可能施加的最大潜在负担。
因此,减少系统中所有程序单元之间的最大潜在依赖关系数会降低对特定程序单元的影响将导致对其他程序单元进行更新的可能性,从而减少所有更新的最大潜在负担。
因此,封装是面向对象的基石,封装有助于我们减少所有程序单元之间的最大潜在依赖关系,并减轻负担原则的弱形式。
【讨论】:
我是一名长期的过程 PHP 程序员,偶尔会涉足面向对象的 PHP。上面乔尔的回答是对好处的一个很好的总结。在我看来,一个微妙的次要好处是它迫使您从一开始就更好地定义您的需求。您必须了解对象之间的关系以及对它们起作用的方法。
帮助过渡的好书是 Peter Lavin 的“面向对象的 PHP”。
【讨论】:
大型系统(例如 Wordpress、Drupal 或 XOOPS)使用 OOP 概念。您可以在那里看到使用它们的好处。代码重用、模块化、可维护性和可扩展性。
您可以修改部分对象,这会影响整个应用程序;没有搜索来替换您执行某些操作的每个位置(并且可能会丢失它)。
您可以重复使用所有对象,从而节省大量复制和粘贴。修补错误需要修补一个对象,而不是 16 页的代码都做同样的事情。
当您封装逻辑并“隐藏”实现时,使用对象会更容易,无论是从现在起 6 个月后,当您忘记自己为什么做某事时,还是对于使用您的代码的窝里的家伙或女孩.例如,您在 Wordpress 中循环浏览帖子所要做的就是调用一个函数。我不需要知道它是如何工作的,我只需要知道如何调用它。
OOP 实际上是包装在对象方法/函数中的过程代码。您仍然需要知道如何编写体面的线性代码才能实现对象的方法和功能。它只是让重用、扩展、修复、调试和维护您的东西变得更加容易。
【讨论】:
【讨论】:
我想说有两个主要好处:
重用我不会严格限定为 OO 的好处,因为在纯过程模型中,智能库组织也允许您重用代码。
另一方面,与过程模型相比,在 PHP 中使用大量对象往往会降低性能,因为每个请求都有太多的对象构造开销。在过程式代码和 oo 式代码之间找到良好的平衡势在必行。
【讨论】:
要学习 PHP 中的 OO,我建议尝试使用一些编写好的 OO PHP 框架。
你可能想看看Zend Framework。
【讨论】:
我也是一个 PHP 人,虽然我确实有很强的 OOP 背景,但我想说最好的关于在 PHP 中使用 OOP 的书必须是 PHP 5 Objects Patterns and Practice
【讨论】:
我在 PHP 中使用 OOP 做的最好的事情之一就是类生成器。 在任何给定的表中,都会涉及几乎相同的 SQL 操作:
现在我不必再编写所有这些 SQL 语句了,除非有特殊情况。我不仅将编码时间缩短到了 1 分钟,而且还节省了调试代码的时间。
所以每当表结构发生变化时,我只需重新生成类。
也许你应该尝试同样的方法,因为它对我和我的客户都喜欢!
【讨论】: