最简单的Web部件和最复杂的在线电子商务Web站点具有一个共同点:它们都要处理数据。大量的编程都设计数据的访问和操作。随着Internet的发展、脸颊存储设备应用数据的大量增长、对分析论的更深入理解以及对数据访问的更大期待,数据以更加有趣和独特的方式受到影响。数据访问设计模式的目的是帮助构造出能够容易地处理素有这些数据的对象。
数据访问对象设计模式描述了如何创建提供透明访问任何对象源的对象。
数据访问对象设计模式的目的是结局一下两种特定的问题:重复与数据源抽象化。
我们应当创建一个数据访问对象设计模式的对象。这个数据访问对象封装了创建sQL调用、减少实例创建的复杂性和重复以及更新进程的智能方式,其编写方式应当是:该对象的使用者不会知道实际使用的表结构和数据库引擎。此外,这个对象应用的方法应当使用逻辑参数,并且应处理SQL语句的创建工作。
数据访问对象模式的额外优点是提供数据库抽象层。现在,应用程序的主要处理代码不再需要考虑数据库引擎或表关系。调用这种对象的公共方法会返回任何数据类型,并且不用考虑内在SQL需要的类型。
使用将非规格化表与另一个表相连接以提供特定结果集的关系数据库结构能够很好地说明这个问题。如果数据库管理员将非规格化表结构修改为完全规格化的,那么遍布应用程序中所有模块的每条SQL语句都需要被修改为添加额外的连接表。如果使用数据访问对象,那么就只需要编辑提供该信息的方法。再来看一下实绩表结构发生变化的情况:对一个列的命名可能发生变化,或者可能添加额外的列。同样地,需要编辑代码的仍然是数据访问对象。SQL纯粹主义者会坚决主张添加的表列应当完全不影响查询,他们认为应当使用SQL语句中指定列。
如果编程人员没有采用数据访问对象设计模式,那么总是会出现问题。将这些对象类型的全部与易于使用相对比,无疑添加更多功能的诱惑占了统治地位。
管理数据访问对象类中简单性的一个好办法是创建父-子关系。首先,创建一个基本的父对象。这个对象应当负责数据库连接、抽象地执行查询以及与子对象通信。使用数据访问对象设计模式时,最好开始就将一对一关系的子类与数据库中的表相关联。这些子类具有必不可少的信息,如表名和主键。此外,子类可能包含一些特定的公共方法,这些方法通过只对子类有意义的方式执行父类的查询。例如,名为userAddress的子类可能包含一个getAddreddesByZip()方法。将该方法放入父DAO类是毫无逻辑意义的,并且会破坏这个父类希望实现的抽象性。
处理引用特定数据库信息的实体时,最好的做法是创建一个数据访问对象。
1 /* 2 *MySQL数据库拥有一条记录,该记录包含对每个用户来说都是具体和特有的信息。这种功能性必须允许我们通过用户的主键或对用户名称的查找返回一个用户。此外,我们必须能够对用户实体记录的任意字段执行更新操作。 3 针对此需求,需要使用两个类:第一个类应当是基本数据访问对象类,它具有获取和更新数据方法: 4 * */ 5 6 abstract class baseDAO{ 7 private $__connection; 8 9 public function __construct(){ 10 $this->__connectionToDB(DB_USER,DB_PASS,DB_HOST,DB_DATABASE); 11 } 12 13 private function __connectToDB($user,$pass,$host,$database){ 14 $this->__connection = mysql_connection($host,$user,$pass); 15 mysql_select_db($database,$this->__connection); 16 } 17 18 public function fetch($vale,$key = NULL){ 19 if(is_null($key)){ 20 $key = $this->_primaryKey; 21 } 22 23 $sql = "select * from {$this->_tablename} where {$key} = '{$value}'"; 24 25 $results = mysql_query($sql,$this->__connection); 26 27 $rows = array(); 28 29 while($result = mysql_fetch_array($results)){ 30 $rows[] = $result; 31 } 32 33 return $rows; 34 } 35 36 37 public function update($keyedArray){ 38 $sql = "update {$this->_tableName} set "; 39 40 $updates = array(); 41 42 foreach($keyedArray as $column =>$value){ 43 $updates[] = "{$column} = '{$value}'"; 44 } 45 46 $sql .= implode(',',$updates); 47 48 $sql = " where {$this->_primaryKey} = '{$keyedArray[$this->_primaryKey]}'"; 49 50 mysql_query($sql,$this->__connection); 51 } 52 } 53 54 /* 55 这是一个抽象类,为了能够使用该类必须扩展该类。 56 因为很可能会同时打开多个数据库连接,所以在数据访问对象类中存储内部的数据库连接并且每个查询都进行引用是十分重要的。这个数据访问对象类应当唯一地引用自其自己的连接。通常,在更多可拓展的模型中,接口被创建用于共享连接。 57 58 */ 59 60 /* 61 任何子类都可以任意扩展这个抽象类: 62 */ 63 64 class UserDAO extends baseDAO{ 65 protected $_tableName = "userTable"; 66 67 protected $_primaryKey = 'id'; 68 69 public function getUserByFirstName($name){ 70 $result = $this->fetch($name,'firstName'); 71 72 return $result; 73 } 74 } 75 76 /* 77 为了获得一个起作用的数据访问对象子实体,至少需要定义两个受保护变量。 78 79 要使用的数据访问对象的示例: 80 */ 81 82 define('DB_USER','user'); 83 84 define('DB_PASS','pass'); 85 86 define('DB_HOST','localhost'); 87 88 define('DB_DATABASE','test'); 89 90 $user = new userDAO(); 91 92 $userDetailsArray = $user->fetch(1); 93 94 $updates = array('id'=>1,'firstName'=>'aaron'); 95 96 $user->update($updates); 97 98 99 $allAarons = $user->getUserByFirstName('aaron');
发现,ThinkPHP数据库操作底层,除了支持多种数据库引擎外,其实原理也是采用这种数据访问对象模式。