_J

please call me j

导航

【Reserved】过程式编程 & 面向对象编程

导读:过程式编程和面向对象编程的区别并不在于是否使用函数或者类,也就是说用到类或对象的可能是过程式编程,只用函数而没有类的也可能是面向对象编程。那么他们的区别又在哪儿呢?

过程式编程

维基百科是这样定义过程式编程的(Procedural Programming):过程式编程某种意义上等同于命令式编程(为了达到预定的状态而执行指定的步骤)的同义词,同时也是一种编程范例(正如本文中所述)——由结构化编程衍生而来,遵循过程调用的观念。

这是一个很恰当的定义,但我们还可以改进它。我更赞同“过程式编程只是一系列为了实现需求功能的特定步骤的命令”这一观点。它究竟是如何实现的只是细节,与范例无关,重要的是它是工作所必要的。先来看几个例子:

这个很明显是过程式编程:


  1. $m = mysqli_connect(...); 
  2. $res = mysqli_query($m, $query); 
  3. $results = array(); 
  4. while ($row = mysqli_fetch_assoc($res)) { 
  5.     $results[] = $row; 

虽然用到了对象,但它实际上也是过程式编程:


  1. $m = new MySQLi(...); 
  2. $res = $m->query($query); 
  3. $results = array(); 
  4. while ($row = $m->fetch_assoc($res)) { 
  5.     $results[] = $row; 

即使使用了类,它还是过程式编程:


  1. class GetResults { 
  2.     public function getResults() { 
  3.         $m = new MySQLi(...); 
  4.         $res = $m->query($query); 
  5.         $results = array(); 
  6.         while ($row = $m->fetch_assoc($res)) { 
  7.             $results[] = $row; 
  8.         } 
  9.         return $results; 
  10.     } 

注意:上述几个例子使用了完全相同的代码框,它们之间的不同点在于如何实现的,但都是过程式编程,都包含必须的独立步骤。再来看看什么才是面向对象编程,它们之间的不同之处又在哪?

面向对象编程

维基百科上是这样定义面向对象编程(Object-Oriented Programming)的:面向对象编程是使用对象的编程范式——包含数据域、方法以及它们之间的交互——来设计应用和程序。编程技术包括包括数据抽象、封装、通信、模块化、多态和继承。

这个定义也不错,但我只同意它的第二部分。第一部分所说的“必须使用对象来做面向对象编程”很明显是错误的,你完全可以通过数据抽象、封装、通信、模块化、多态和继承等方式实现数据抽象。

我对于面向对象编程的几点理解是:

  • 首先,它必须将数据抽象为模块结构;
  • 其次,必须存在某种方式来实现代码的多态执行;
  • 最后,它至少能部分压缩代码和函数。

下面再看看几个例子:

经典面向对象编程模式:


  1. class Mediator { 
  2.     protected $events = array(); 
  3.     public function attach($eventName, $callback) { 
  4.         if (!isset($this->events[$eventName])) { 
  5.             $this->events[$eventName] = array(); 
  6.         } 
  7.         $this->events[$eventName][] = $callback; 
  8.     } 
  9.     public function trigger($eventName, $data = null) { 
  10.         foreach ($this->events[$eventName] as $callback) { 
  11.             $callback($eventName, $data); 
  12.         } 
  13.     } 
  14. $mediator = new Mediator; 
  15. $mediator->attach('load', function() { echo "Loading"; }); 
  16. $mediator->attach('stop', function() { echo "Stopping"; }); 
  17. $mediator->attach('stop', function() { echo "Stopped"; }); 
  18. $mediator->trigger('load'); // prints "Loading" 
  19. $mediator->trigger('stop'); // prints "StoppingStopped" 

相同的模式,但使用函数:


  1. $hooks = array(); 
  2. function hook_register($eventName, $callback) { 
  3.     if (!isset($GLOBALS['hooks'][$eventName])) { 
  4.         $GLOBALS['hooks'][$eventName] = array(); 
  5.     } 
  6.     $GLOBALS['hooks'][$eventName][] = $callback; 
  7. function hook_trigger($eventName, $data = null) { 
  8.     foreach ($GLOBALS['hooks'][$eventName] as $callback) { 
  9.         $callback($eventName, $data); 
  10.     } 

如你所见,它们都遵循传递者模式(Mediator Pattern),并且被设计为从sender中解耦caller,所以都是面向对象的。都提供状态、都是模块化的。不同点在于:第一个是通过传统的类实现的(因此可重用,这也是使用类的一个优势),而第二个使用了全局变量,并不可重用。我在这里使用“hook”,这是一个Drupal使用的事件系统。

Drupal是一个很好的例子,它的模块系统、“hook”系统、结构系统都是面向对象的,但都不是使用对象实现的,它是使用函数和动态分配,这导致了很多尴尬的折中,我并不是说这是一个好的面向对象,只是证明类并不是面向对象编程所必须的因素。

为什么这很重要?

很简单,因为很多开发者认为他们使用了类就是在做面向对线编程;另一些人认为他们使用函数就是在做过程式编程了,这并不正确。过程式编程和面向对象编程都是一种写代码的途径,而不是你写代码的手段。你会遵循步骤,按照设定好的方式去编写程序吗?你看起来是在函数式编程,但是如果你专注于状态改变和密封抽象,你就是在用面向对象编程。

类只是帮助简化面向对象编程的工具,并不是面向对象编程的要求或指示器。

面向对象编程与数据库存取

那面向对象编程里的数据库存取又是什么样的呢?面向对象编程的数据库存取是完全抽象的,我的方法是:


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

people是一个person对象的数组。注意:像这样抽象很有必要,所以事物对象无法直接对数据库操作,你需要一个映射器来翻译事物对象和数据存储之间的转换。一个专门的映射器会在内部创建请求,执行并返回结果。但这完全是抽象的,我们可以简单地换掉映射器来改变数据库层实现细节。

数据持久化的责任变成了封装抽象,这也就是为什么它是面向对象编程而不是过程式编程。

原文链接:blog.ircmaxell.com

本文为CSDN原创文章,未经允许不得转载。如需转载请联系market@csdn.net。

posted on 2012-09-03 00:19  _J  阅读(180)  评论(0编辑  收藏  举报