到目前为止,您所看到的这些设计模式大大提高了代码的可读性与可维护性。然而,在WEB应用设计与开发中一个基本的需求与挑战:数据库应用,这些设计模式都没有涉及到。本章与接下来的两章—表数据网关与表数据映射,提供了三种设计模式使您能更好的组织你的应用程序与数据库进行交互。
问题
大多数WEB应用将信息持续保存在数据库中。有将数据库操作抽象化,以达到简化表数据存取和对业务逻辑的集成存取方法吗?
解决方案
理论上,动态记录模式是最简化的有关数据库的设计模式。动态记录模式包含了如何在类中直接实现与数据库交互的相关知识。
动态记录模式在程序代码与数据库结构之间产生了一种很高的结合度,在一些相对简单的应用环境中,就能比采用别的复杂方案更容易解决这种因结合所产生的一些固有问题。动态记录模式也能满足许多初级的数据库项目。只有当复杂性增加而难以用动态记录模式处理时,你才有必要使用表数据网关模式(参见15章),或是数据地图模式(参见16章)或是别的数据库设计模式
企业级应用架构模式
根据Martin Fowler’s的著作《企业级应用架构模式》,所谓企业级应用就是与别的应用集成化,包含了重要的业务逻辑(或如应用需求所呈现的非逻辑的东西),并且具有许多并发存取和保存从各种接口取得的数据。有趣的是,web应用正好具备了上述多个特点,这正好能解释为什么Martin Fowler’s的著作能引起PHP程序员的强烈反响。
PHP数据对象
PDO是一个高性能的数据库通道接口(并非数据库抽象)。PDO是一个由C语言构成的本地驱动包,因此其速度是很快的。PDO为所有的PDO驱动提供了申明,增强了脚本使用库时的安全性。
样本代码
任何对数据库连接的讨论都依赖于对数据库系统与对数据库访问层的选择。本章与随后两章都使用MYSQL(http://www.mysql.com/)这个流行的开源数据库及ADOdb (http://adodb.sf.net/)作为数据库访问层。我将ADOdb作为我自己工作室的标准是因为它优异的性能,且抽象了Oracle OCI接口,并提供了统一的访问PostgreSQL, Sybase, MySQL和其它数据库的接口,而成为了易于使用的PHP API,让你专注于程序与业务逻辑的处理。
放心的替换你的自己的数据库与访问层,因为这里提出的许多概念也适合于别的解决方案。
在研究t动态记录模式之前,让我们从基本的数据库连接开始。有一个集中的,简单的方式去指定连接参数(主机名,用户名,密码,数据库)并建立一个数据库连接对象是很理想的。一个单一模式对象(参见第四章)就非常适合了。
这是一个DB类,其conn()方法返回一个单一模式的ADOConnection类的实例。
// PHP5 require_once ‘adodb/adodb.inc.php’; class DB { //static class, we do not need a constructor private function __construct() {} public static function conn() { static $conn; if (!$conn) { $conn = adoNewConnection(‘mysql’); $conn->connect(‘localhost’, ‘username’, ‘passwd’, ‘database’); $conn->setFetchMode(ADODB_FETCH_ASSOC); } return $conn; } } |
DB类允许你设定数据库的类型与连接参数。第一行代码将ADOdb库包含进来(你可能需要根据你的实际环境来调整路径);因为没有必要每次都实例化DB,所以DB的构造函数是私有的; 行$conn->setFetchMode(ADODB_FETCH_ASSOC)设定对象返回的记录集是以(字段名=>值)形式的关联数组。与数据库打交道中采用关联数组是非常重要的经验习惯,这样您的代码就不会受到因SQL语句中字段排序而产生的影响。
作为示例程序,让我们建立一个Active Record对象来维护一个超链接表。以下是一个在MySQL数据库中建立这个超链接表的SQL。
define(‘BOOKMARK_TABLE_DDL’, <<<EOS CREATE TABLE `bookmark` ( `id` INT NOT NULL AUTO_INCREMENT , `url` VARCHAR( 255 ) NOT NULL , `name` VARCHAR( 255 ) NOT NULL , `description` MEDIUMTEXT, `tag` VARCHAR( 50 ) , `created` DATETIME NOT NULL , `updated` DATETIME NOT NULL , PRIMARY KEY ( `id` ) ) EOS ); |
实验的独立性
各个实验间应是相互独立的;否则,仅仅是运行了某一个实验就会影响到后续实验的结果。
为了避免这些都基于同一数据库的实验间相互干扰,最好是在每个测试开始前删除并重建相关表。以下简单的实验为后续实验提供了一种标准的setup方法。
以下代码演示如何在每个实验开始前重置你的数据库:
class ActiveRecordTestCase extends UnitTestCase { protected $conn; function __construct($name=’’) { $this->UnitTestCase($name); $this->conn = DB::conn(); } function setup() { $this->conn->execute(‘drop table bookmark’); $this->conn->execute(BOOKMARK_TABLE_DDL); } } |
这段代码用一个标准的ADOConnection对象来给$conn的属性赋值,并且使用了Connection的execute()方法来执行SQL删除与重建表的操作。因为这些代码在一个名为setup()的方法中,使得每一个实验都能在一个新的数据库环境中工作。
延伸阅读:
从魔兽看PHP设计模式
《PHP设计模式介绍》导言
PHP设计模式介绍 第一章 编程惯用法
PHP设计模式介绍 第二章 值对象模式
PHP设计模式介绍 第三章 工厂模式
PHP设计模式介绍 第四章 单件模式
PHP设计模式介绍 第五章 注册模式
PHP设计模式介绍 第六章 伪对象模式
PHP设计模式介绍 第七章 策略模式
PHP设计模式介绍 第八章 迭代器模式
PHP设计模式介绍 第九章 观测模式
PHP设计模式介绍 第十章 规范模式
PHP设计模式介绍 第十一章 代理模式
PHP设计模式介绍 第十二章 装饰器模式
PHP设计模式介绍 第十三章 适配器模式