我如何摆脱程序编程和面向对象编程的习惯?

时间:2009-12-08 22:04:52

标签: php oop procedural-programming

我希望得到一些提示,以帮助我突破我在这些年后所考虑的程序编程的坏习惯。每当我尝试在OOP中完成一个项目时,我最终都会恢复到程序化。我想我并不完全相信OOP(尽管我认为我听说过一切都很好!)。

所以我想我常常执行的常见编程任务的任何好的实际例子,例如用户身份验证/管理,数据解析,CMS / Blogging / eComs都是我经常做的事情,但我还没能做到让我了解如何在OOP中完成它们并远离程序,特别是当我构建的系统倾向于工作和运行良好时。

我可以看到,作为我的开发失败的一件事是,我经常重复使用我的代码,而且它经常需要更多的重写和改进,但我有时会认为这是我的软件开发的自然演变。

但我想改变!对我的同事们,帮助:)关于如何摆脱这种令人讨厌的习惯的任何提示?

20 个答案:

答案 0 :(得分:20)

当你找不到合理的理由或动机时,使用面向对象编程有什么意义呢?

你必须以想象和操纵想法作为对象的需要为动力。有些人认为需要敏锐地理解概念,流程或功能而不是对象,然后他们会被激发出面向概念,思想或功能流程的编程。

大约13年前,我从c切换到c ++只是因为我需要的想法但c不会轻易执行。简而言之,我的需求促使我的编程面向对象。

面向对象的思维模式

首先,你有字节,字符,整数和浮点数。

然后你的程序开始混乱各种变量,本地和静态。 然后你决定将它们分组为结构体,因为你想到了所有通常传递的变量。

数据集合

因此,打印机的信息应该将其所有变量都包含在Printer结构中:

{id, name, location,
 impactType(laser|inkjet|ribbon),
  manufacturer, networkAddr},
  etc.

现在,当您通过打印机信息调用函数后,您没有具有长参数列表的函数或具有大量串扰可能性的大量静态变量。

纳入信息

但数据集合还不够好。我仍然需要依赖一堆函数来处理数据。因此,我有一个聪明的想法或将函数指针合并到Printer结构中。

{id, name, location,
 impactType(laser|inkjet|ribbon),
 manufacturer, networkAddr,
 *print(struct printer),
 *clean(struct printer)
}

当数据包含有关如何处理/感知数据的过程时,数据会逐渐变为信息。

信息量化

现在,激光,色带和喷墨打印机并不都具有相同的信息集,但它们都有一组最常见的分母(LCD)信息:

任何打印机通用的信息:ID,名称,位置等

仅在色带打印机中发现的信息:usedCycles,ribbon(fabric | cellophane),colourBands等

仅在喷墨中发现的信息:墨盒等

仅在激光中发现的信息:...

对于我和许多面向对象的同类群组,我们更倾向于将所有常见信息量化为一个公共信息封装,而不是为每种打印机类型定义单独的结构/封装。

然后,我们更喜欢使用一个框架来管理每种类型打印机的所有功能参考,因为并非所有打印机都以相同的方式打印或清理。

因此,如果您不使用对象,那么您偏离对象的偏好/动机会告诉您编程生活会更容易吗?您更愿意自己管理所有这些结构复杂性。你一定不能写出足够的软件来感受那种方式。

懒惰的必要性

有些人说 - 必要性是创造力的母亲。 (以及对金钱的热爱是邪恶的根源。)

但对我和我的同伴 - 面对必要性的懒惰是创造力的父母。 (以及缺钱是另一个邪恶的父母)。

因此,我敦促你对编程采取一种懒惰的态度,这样最短路径的原则就会进入你的生活,你会发现但除了毕业之外别无选择,只能用自己来定位对象编程。 / p>

答案 1 :(得分:14)

步骤1.阅读一本好的设计模式书。 http://www.oodesign.com/

步骤2.选择您已经知道的东西并从OO角度重新加工。这是Code Dojo方法。解决您已经理解的问题,并定义对象类。

我这样做了 - 并写下了我的所作所为。

请参阅http://homepage.mac.com/s_lott/books/oodesign.html#book-oodesign

你可以做同样的练习,以获得OO设计和代码。

答案 2 :(得分:5)

OO思维模式基于比设计模式更基本的原则。设计模式现在有点流行(并且已经有一段时间了),而且它们 非常有用,但它们只是一层你可以放在更基本的东西上,你绝对必须学习和掌握如果你想正确地做OO。换句话说:你可以在没有设计模式的情况下完美地完成OO。事实上,在“设计模式”这个短语被创造之前,我们中的许多人都做得很好。

现在,有一些你不能没有的东西。我建议你从基础开始。阅读并理解"Object-Oriented Software Construction" 2nd edition by Bertrand Meyer。它可能是关于OO编程的最佳书籍,无论是宽度还是深度。那就是如果你对编程感兴趣。

答案 3 :(得分:4)

首先,恭喜采取措施学习新知识!当开发人员决定不用技术进化时,我讨厌它。

至于从程序编程转向OOP,我会说你可以做的一件事是拿一个现有的应用程序(正如其他人提到的那样),在你打开文本编辑器之前,坐下来思考如何应用程序的每个方面都将被转换。我发现超过一半的OO编程首先在你的脑海中定义概念对象。

同样,我会同意每个人对设计模式的建议。具体来说,我将研究MVC(模型 - 视图 - 控制器)模式,因为这可能是最容易掌握的模式。您已编写代码,因此您应该能够查看现有应用程序并开始将每个部分放入M,V或C类别。

祝你好运,玩得开心!

答案 4 :(得分:3)

关于在面向对象的方式中查找有关编程的信息的位置已经有很多答案。事实上,有许多伟大的书籍将定义基本概念,但我认为问题更多的是关于如何通过开发为该方法的新人“坚持下去”。

在面向对象编程中的许多概念中,作为新手将使您保持正轨的主要概念是封装。我的班级知道如何照顾自己吗?我的班级有行为吗?如果没有,那么你没有一个类,你有一个结构,你可能会写很多程序来改变它的状态(因为它说,“你回来了用Java写“C”。我的班级是否只公开其使用所需的公开方法?这些问题可能没有特别详细说明,但在设计课程时可能会考虑这个思想实验:如果每个应用程序的类都由互联网上的不同开发人员开发和维护,并且类也必须在彼此之间进行交互,那该怎么办?互联网。每个开发人员都会同意他们正在编写和维护的课程遵守single responsibility principle,因此很高兴他们不会维护应该成为别人的代码吗?

关于类接口的设计,请考虑首先编写所有使用类的代码。不要担心金属会发生什么。在编写第一个比特错误的实现细节之前,您应该能够根据类关系来存根整个程序。如果你不能在没有繁琐的位置或公开变量的情况下做到这一点,那么现在是时候回到你的类关系图,看看你是否缺少抽象。换句话说,在编写代码之前使用代码。首先执行此操作,如果您以前从未完成过,那么您可能会对代码和界面的干净程度感到惊讶。

虽然设计模式肯定是好学的,有些非常强大,但它们通常不是本质上面向对象的,而且有些人认为(我倾向于同意)设计模式通常只是暴露在语言中的弱点。一种语言的设计模式是另一种基本的基本原则。因此,在开始时,不要挂断一些关系是否适合桥梁或立面;这不是特定于面向对象的思想,这与特定语言的构造所支持的内容有关。

答案 5 :(得分:2)

我认为首先浏览一些现有的,体面的,经过验证的面向对象的代码(例如Qt源代码)是有帮助的,这样你就可以了解“它是如何完成的”。在那之后,从书中学习或创建自己的框架将会更加有效。

一般来说,在阅读和练习它们之前先看看事物是非常有帮助的,因为它让你有时间对自己说,“哦,这就是他们这样做的原因!”至少这对我有用。

答案 6 :(得分:2)

OO的难点在于将哪些东西放在一个对象中。正如您已经提到过源代码的演变,这里有一个关于如何将源代码演变为OO设计的简单指南:

"Put stuff together that changes together."

当两段代码具有相似的变化速度时,这暗示它们应该放在同一个对象中。当变化速度不同时,请考虑将它们放在不同的物体中。

这也称为“改变速度”。

如果您遵循该指南,您的代码将自然地朝着良好的OO设计发展。为什么呢?

  

代码片段通常有类似的   如果他们访问a,则改变速度   共同代表。每一次   代表性的变化,所有的碎片   使用它的代码必须改变   一旦。这是我们的部分原因   使用对象作为封装的模块   表示。分离界面   从实施有意义   这条准则也是 -   实施变更更频繁和   因此具有更高的变化速度。

     

如果一个班级有一个稳定的部分和一个   不稳定的部分,这是一个区别   改变表明移动的速度   稳定的一部分(可能是   抽象)基类。

     

同样,如果一个班级有两个部分   它经常变化,但在   不同的时间或不同的   方向(也就是说   不同的原因),然后再说   建议重构课程。

     

有时用“class”替换   “方法”。例如,如果一行   一种方法可能会发生更多变化   经常比其他人 - 也许是   创建新对象的行   实例并包含其名称   class - 考虑将其移至自己的位置   常规。然后子类很容易   通过覆盖来改变他们的变化。

我遇到了这个概念on C2 wiki many years ago,但我很少见到它。我发现它非常有用。它表达了面向对象设计的一些重要的潜在动机。当然,它显然是非常明显的。

  

这些是程序的变化。   还有另一种变化感   速度 - 你不想要实例   变量以不同的速率变化,   或者更确切地说,这是潜在的迹象   问题。例如,在图形中   编辑你不应该保留数字   和手柄相同   收集,因为数字变化   每分钟一次或每小时一次   处理每秒更改一次或一次更改   分钟。

     

在更大的视图中,你需要一个   系统能够快速改变   足以跟上变化   业务。

PS:你应该遵循的另一个原则是“德米特法则”,即一个物体应该只与它的朋友交谈。朋友是:你自己,实例变量,参数,本地人和友好集合的成员 - 但是不是全局变量和静态变量。

答案 7 :(得分:2)

您可以考虑使用CRC(类/责任/协作)卡方法进行OO设计。这并不是什么太可怕 - 只是一种方法来理清你的对象应该是什么,以及哪些对象应该通过在一堆文件卡上写下东西来帮助澄清你的想法来负责哪些任务。

它最初被设计为OO思想的教学工具,可能适合您。原始论文位于:http://c2.com/doc/oopsla89/paper.html

上面的海报建议在Smalltalk中编程以迫使你进入OO习惯,并且在某种程度上这是一个很好的建议 - Smalltalk确实给了我很多好处,但是

a)您可能没有空余时间学习新语言。如果你这样做,那很好。

b)我曾经使用Smalltalk在OO编程中辅导大学课程,学生们非常出色地证明了“你可以用任何语言编写FORTRAN”这个老笑话。

最后:当我学习OO(来自书籍)时,我得到的印象是你创建了很多子类,创建了复杂的类层次结构。当我开始与OO程序员合作时,我意识到它并没有像我想象的那样经常发生。我认为每个人在学习时都会犯这个错误。

答案 8 :(得分:1)

别。

首先,学习写作。其次,学习用户体验和交互设计。第三,学习业务分析。第四,学习角色建模。

现在你知道了什么是对象,你会发现在代码中找不到对象。它们是在运行时发现的;在机器和用户心灵之间的空间。这就是面向对象的真正含义。不幸的是,最近学术界已将其扭曲为工程概念。没有什么比这更进一步了。并尝试尽可能模仿,最终结果是垃圾。为什么?因为业界今天所知道的“OOP”范式建立在一个根本上有缺陷的观念上:对身份的分解分析。这有什么缺陷?因为身份本身是没有意义的。它是无效的。在数学意义上,在哲学意义上。这不是人类如何感知和与世界互动。

佳能:Alan Kay,Trygve Reenskaug,James(Jim)Coplien

我多么希望自己能够胜任。 :)

答案 9 :(得分:1)

我发现其中一个真正有助于巩固OOP优势的事情就是使用模拟对象框架(例如EasyMock)编写单元测试。一旦开始以这种方式开发,您就可以看到类如何帮助您隔离接口后面的模块,并且还允许更容易的测试。

要记住的一件事是,当人们第一次学习OOP时,往往会过分强调继承。继承有它的位置,但它是一个很容易被滥用的工具。组合或简单的界面实现通常是更好的做事方式。在尝试通过继承重用代码时,不要过多地使用继承树,这从多态性的角度来看是没有意义的。替换原则是使继承/接口实现功能强大的原因,而不是通过子类化可以重用代码的事实。

答案 10 :(得分:1)

好吧,首先,设计模式是编程模式最糟糕的事情。

这只是一大堆事情。它与OOP无关,而且其中大多数如单例都经常被用于所有错误的原因(即初始化)。你必须使用其中一些东西来告诉你它们是毫无意义的,其他的则适得其反,其余的只是特殊情况。如果你试图以这种方式学习任何东西,一切都将开始看起来像一个奇怪的doodad有人想出一个非常特殊的问题,或者因为他们需要无限的通用性(这很少是真的)。不要让人们无缘无故地使用百万个迭代器和模板,并使事情变得复杂十倍。

真正的OOP是一个简单过分复杂的简单主题。不幸的是,在C ++中它有很多问题,但真正简单的虚拟方法才是最重要的。像java接口对象一样使用的纯虚拟基类是最有用的,但也只是普通的虚拟方法,并且会派上用场。

这大多被夸大了。它也不适合每一个问题。如果你制作数据库和gui的东西,它很适合。如果你制作系统工具,通常没那么有用。

答案 11 :(得分:1)

对我来说,OOP的时刻是我第一次查看代码并意识到我可以将常见的东西重构为基类。你清楚地了解代码和重用的方法,但你需要考虑类而不是程序。使用用户身份验证很明显你将拥有一个用户名和密码,现在他们进入基类,但如果你需要一个tokenId,重新使用你现有的登录基类,并从中创建一个新的子类使用新行为,所有现有代码都可以正常运行。

了解这对您有何帮助。

答案 12 :(得分:1)

我认为你应该通过程序编程研究所有的缺点来说服自己,例如(一些流行语跟随,注意):范围,状态......实际上你只需通过阅读例子就可以提取很多术语设计模式(阅读:一起使用对象的常见例子。)

强调自己学习一些你不相信的东西不会让你无处可去。开始对你早期的工作非常关键并重构它以避免复制代码和使用全局范围,你会发现自己想要更多。

答案 13 :(得分:1)

编写更好代码的唯一方法是编写更多代码。以程序方式实现的项目并将其转换为OOP(假设您使用支持两者的语言)。第一次你可能最终得到一个脆弱的,紧密耦合的解决方案,但没关系。采取糟糕的OOP实现并开始将其重构为更好的东西。最终,你会弄清楚哪些有效,哪些无效。

当您准备好进行下一步时,请选择Design Patterns一书并学习一些OOP设计术语。这不是绝对必要的,但它可以让您更好地掌握一些常见问题和解决方案。

答案 14 :(得分:0)

我认为首先学习这个理论很重要。因此,阅读一本书将是一个良好的开端。

答案 15 :(得分:0)

  1. 我相信OOP的机制看起来完全是武断的,直到你读了一本关于设计模式的书并理解它的“原因”之后才会有意义。我推荐Head First Design Patterns。我认为OOP是荒谬的,完全没用,直到我拿起这本书并看到它真正有用的东西。

  2. 当您理解函数指针及其与间接函数调用和后期绑定的关系时,OO更有意义。在C,C ++或D中使用函数指针一段时间,并了解它们的用途以及它们的工作原理。 OO的多态/虚函数部分只是另一个抽象层。

  3. 程序是一些工作的正确工具。不要表现得像是错的。恕我直言,所有三个主要范例(程序,OO,功能)都是有价值的,即使在细粒度的水平上,在单个模块中。我倾向于选择:

  4. 当我的问题很简单时,程序是好的(或者我已经用功能和OO对它进行了足够的考虑,我现在有一个我认为很简单的子问题)并且我想要最简单的解决方案而不需要很多抽象方式。

    当我的问题更复杂并且在问题域的上下文中有许多有意义的状态时,面向对象是好的。在这些情况下,状态的存在不是一个实现细节,但确切的表示是我更喜欢抽象的。

    当我的问题很复杂但没有在问题域的层面上有意义的状态时,功能是好的。从问题域的角度来看,状态的存在是一个实现细节。

答案 16 :(得分:0)

学习一种新语言,这种语言可以帮助你轻轻地移动到OOP。 Java很好,但有点臃肿。但它的系统库主要是OO,所以你强迫使用对象。 迁移到另一种语言也可以帮助您重用旧代码: - )

答案 17 :(得分:0)

简单练习。如果您已经阅读了有关OOP的所有内容,并且您知道关于OOP的某些内容,并且您知道使用您的语言PHP实现的OOP主体...那么只需练习,练习和练习一些。

现在,不要将OOP视为锤子以及其他所有东西作为钉子,但是要尝试在项目中至少包含一个类。然后看看你是否可以在另一个项目等中重复使用它。

答案 18 :(得分:0)

一个很好的步骤是开始使用OOP框架,你仍然可以在框架中编写程序代码,但随着时间的推移,你可以改进你的编码习惯。开始将功能转换为对象。

还阅读有关模式和&数据建模将为您提供更多关于以OOP风格编写逻辑的想法。

答案 19 :(得分:0)

我发现学习编程抽象编程的一种非常激烈的方法是构建一个具有已定义功能的OOP库,然后在同一个库上构建具有相似但仍然不同的需求的两个项目时间。

这非常耗时,您需要首先学习OOP的基础知识(S.Lott在另一个答案中有一些很棒的链接)。不断的重构和很多“Doh!”时刻是规则;但我发现这是学习模块化编程的好方法,因为我所做的一切在其中一个项目的实施中立即引人注目。