数据源架构模式之活动记录
【活动记录的意图】
一个对象,它包装数据表或视图中某一行,封装数据库访问,并在这些数据上增加了领域逻辑。
【活动记录的适用场景】
适用于不太复杂的领域逻辑,如CRUD操作等。
【活动记录的运行机制】
对象既有数据又有行为。其使用最直接的方法,将数据访问逻辑置于领域对象中。
活动记录的本质是一个领域模型,这个领域模型中的类和基数据库中的记录结构应该完全匹配,类的每个域对应表的每一列。
一般来说,活动记录包括如下一些方法:
1、由数据行构造一个活动记录实例;
2、为将来对表的插入构造一个新的实例;
3、用静态查找方法来包装常用的SQL查询和返回活动记录;
4、更新数据库并将活动记录中的数据插入数据库;
5、获取或设置域;
6、实现部分业务逻辑。
【活动记录的优点和缺点】
优点:
1、简单,容易创建并且容易理解。
2、在使用事务脚本时,减少代码复制。
3、可以在改变数据库结构时不改变领域逻辑。
4、基于单个活动记录的派生和测试验证会很有效。
缺点:
1、没有隐藏关系数据库的存在。
2、仅当活动记录对象和数据库中表直接对应时,活动记录才会有效。
3、要求对象的设计和数据库的设计紧耦合,这使得项目中的进一步重构很困难
【活动记录与其它模式】
数据源架构模式之行数据入口:活动记录与行数据入口十分类似。二者的主要差别是行数据入口 仅有数据库访问而活动记录既有数据源逻辑又有领域逻辑。
【活动记录的PHP示例】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | <?php /** * 企业应用架构 数据源架构模式之活动记录 2010-10-17 sz * @author phppan.p#gmail.com http://www.phppan.com * 哥学社成员(http://www.blog-brother.com/) * @package architecture */ /** * 定单类 */ class Order { /** * 定单ID * @var <type> */ private $_order_id; /** * 客户ID * @var <type> */ private $_customer_id; /** * 定单金额 * @var <type> */ private $_amount; public function __construct($order_id, $customer_id, $amount) { $this->_order_id = $order_id; $this->_customer_id = $customer_id; $this->_amount = $amount; } /** * 实例的删除操作 */ public function delete() { $sql = "DELETE FROM Order SET WHERE order_id = " . $this->_order_id . " AND customer_id = " . $this->_customer_id; return DB::query($sql); } /** * 实例的更新操作 */ public function update() { } /** * 插入操作 */ public function insert() { } public static function load($rs) { return new Order($rs['order_id'] ? $rs['order_id'] : NULL, $rs['customer_id'], $rs['amount'] ? $rs['amount'] : 0); } } class Customer { private $_name; private $_customer_id; public function __construct($customer_id, $name) { $this->_customer_id = $customer_id; $this->_name = $name; } /** * 用户删除定单操作 此实例方法包含了业务逻辑 * 通过调用定单实例实现 * 假设此处是对应的删除操作(实际中可能是一种以某字段来标记的假删除操作) */ public function deleteOrder($order_id) { $order = Order::load(array('order_id' => $order_id, 'customer_id' => $this->_customer_id)); return $order->delete(); } /** * 实例的更新操作 */ public function update() { } /** * 入口类自身拥有插入操作 */ public function insert() { } public static function load($rs) { /* 此处可加上缓存 */ return new Customer($rs['customer_id'] ? $rs['customer_id'] : NULL, $rs['name']); } /** * 根据客户ID 查找 * @param integer $id 客户ID * @return Customer 客户对象 */ public static function find($id) { return CustomerFinder::find($id); } } /** * 人员查找类 */ class CustomerFinder { public static function find($id) { $sql = "SELECT * FROM person WHERE customer_id = " . $id; $rs = DB::query($sql); return Customer::load($rs); } } class DB { /** * 这只是一个执行SQL的演示方法 * @param string $sql 需要执行的SQL */ public static function query($sql) { echo "执行SQL: ", $sql, " <br />"; if (strpos($sql, 'SELECT') !== FALSE) { // 示例,对于select查询返回查询结果 return array('customer_id' => 1, 'name' => 'Martin'); } } } /** * 客户端调用 */ class Client { /** * Main program. */ public static function main() { header("Content-type:text/html; charset=utf-8"); /* 加载客户ID为1的客户信息 */ $customer = Customer::find(1); /* 假设用户拥有的定单id为 9527*/ $customer->deleteOrder(9527); } } Client::main(); ?> |
同前面的文章一样,这仅仅是一个活动记录的示例,关于活动记录模式的应用,可以查看Yii框架中的DB类,在其源码中有一个CActiveRecord抽象类,从这里可以看到活动记录模式的应用
另外,如果从事务脚本中创建活动记录,一般是首先将表包装为入口,接着开始行为迁移,使表深化成为活动记录。
对于活动记录中的域的访问和设置可以如yii框架一样,使用魔术方法__set方法和__get方法。