OOP vs 过程式编码

今天早上我被问了一个奇怪的问题:"你那个 PasswordLib的范例是OOP模式的,如果我想用过程式编程解决,那该怎么做?"。这个问题让我想了很久,因为这个功能需求自身就是过程化的。所 以我觉得要写一篇文章来说说OOP与过程式编程的区别了。提示:你是否使用类与对象与最后的答案实际上几乎没关系.

过程式编程
维基百科是这样定义 过程式编程的
Procedural programming can sometimes be used as a synonym for imperative programming (specifying the steps the program must take to reach the desired state), but can also refer (as in this article) to a programming paradigm, derived from structured programming, based upon the concept of the procedure call.
这显示是很正式的定义,我们来看看如何表达得更好,我认为过程式编程就是一步一步完成目标的顺序式步骤行为,每一步都可以完成某个特定的功能。来看看下面这几段代码:

很明显的过程式编码:
1 $m = mysqli_connect(...);
2 $res = mysqli_query($m, $query);
3 $results = array();
4 while ($row = mysqli_fetch_assoc($res)) {
5     $results[] = $row;
6 }

 


下面这个也是过程式编码,但是使用了对象:
1 $m = new MySQLi(...);
2 $res = $m->query($query);
3 $results = array();
4 while ($row = $m->fetch_assoc($res)) {
5     $results[] = $row;
6 }

 


这个也是过程式代码,即使用到了类:

 

01 class GetResults {
02     public function getResults() {
03         $m = new MySQLi(...);
04         $res = $m->query($query);
05         $results = array();
06         while ($row = $m->fetch_assoc($res)) {
07             $results[] = $row;
08         }
09         return $results;
10     }
11 }

 

 

请注意上面的三段代码都是同样的代码结构,都是过程式模式。那么我们来看看OOP模式是如何实现同样的目标。

OOP
维基百科对OOP编程的定义如下:
Object-oriented programming (OOP) is a programming paradigm using "objects" – data structures consisting of data fields and methods together with their interactions – to design applications and computer programs. Programming techniques may include features such as data abstraction, encapsulation, messaging, modularity, polymorphism, and inheritance.

又是一个太正式的定义。但我只认同第二部分的说明。而第 一句话说到你必须使用对象数据结构去写OOP代码实在太过牵强。你可以自己实现数据抽象,封装,消息传递,以及模块化,类集成设计而无需使用对象结构。但 我真正认为OOP之所以为OOP的真正意义是下面几个原因:第一,必须将数据抽象为模块化单元。第二,必须以多态的方式去实现。最后,也必须把功能彻底封 装。只有实现了这几点的才算真正意义的OOP编程。来看看几个典型OOP代码段:


经典OOP模式:

01 class Mediator {
02     protected $events = array();
03     public function attach($eventName, $callback) {
04         if (!isset($this->events[$eventName])) {
05             $this->events[$eventName] = array();
06         }
07         $this->events[$eventName][] = $callback;
08     }
09     public function trigger($eventName, $data = null) {
10         foreach ($this->events[$eventName] as $callback) {
11             $callback($eventName, $data);
12         }
13     }
14 }
15 $mediator = new Mediator;
16 $mediator->attach('load', function() { echo "Loading"; });
17 $mediator->attach('stop', function() { echo "Stopping"; });
18 $mediator->attach('stop', function() { echo "Stopped"; });
19 $mediator->trigger('load'); // prints "Loading"
20 $mediator->trigger('stop'); // prints "StoppingStopped"

 


同样的模式,使用同样的方法。
01 $hooks = array();
02 function hook_register($eventName, $callback) {
03     if (!isset($GLOBALS['hooks'][$eventName])) {
04         $GLOBALS['hooks'][$eventName] = array();
05     }
06     $GLOBALS['hooks'][$eventName][] = $callback;
07 }
08 function hook_trigger($eventName, $data = null) {
09     foreach ($GLOBALS['hooks'][$eventName] as $callback) {
10         $callback($eventName, $data);
11     }
12 }

 


如你所见,这两个都是使用 Mediator Pattern . 。都是基于面向对象的,因为它们都是被设计为 de-couple caller 模式,都提供了状态机以及模块。上面两者的区别就是一个是以传统对象实现的,而另一个全是用全局变量。我这里用专业术语"hook"来解释这个重要的原因。这也是  Drupal  使用的事件消息传递系统。

Drupal 的模块系统是将面向对象表现的非常明显的。比如它的模块系统,hook系统,表单系统等等。但是却没有使用对象。它都是在用实现的方法以及动态的消息分发。这个东西很难去权衡,所以我也并不认为是个好东西,它只是为了去证明你不需要用类或对象来实现OOP。

为什么这个很重要
很多开发者在想因为我要OOP,所以我必须使用类与对 象。还有一些开发者在想因为我要过程化编程所以我只能使用方法。这些都是不好的潜意识。OOP与过程式编程只是你去实现目的的一种方式而已,并不代表你只 有这一种方式。如果你在写代码的时候总是想着一步一步该做什么了,那你只是喜欢这种过程式编码的方式。相反如果你那时总在想着对象状态,消息传递,或者抽 象的封装。那么你就是一个典型的OOP程序员。

而类与对象只是让你更容易使用OOP而已,并不是说用了类就一定是OOP编程。

更新:OOP 数据获取
所以,有些人在问获取数据时如何使用OOP呢。来看看下面这个代码:

 

1 $mapper = new PersonDataMapper(new MySQLi(...));
2 $people = $mapper->getAll();

 


这里的$people就是一个包含大量person的数组。注意这是抽象方式实现的,所以在你的真实项目中你并不知道你是从哪里获取数据的。这里能很容易修改你如何获取数据层的数据。


而这里发现我们需要将数据抽象封装后维持的需求是非常适合OOP模式的,所以在这里不适合过程式编程。

 

转至http://www.oschina.net/question/213217_61704?from=20120729

posted @ 2013-04-25 11:23  beixiao1909  阅读(336)  评论(0编辑  收藏  举报