用 ActiveRecord 更好的封装业务逻辑
时间:2008-04-12 来源:qeeify
通常的 ActiveRecord 实现,无非是封装一个数据库记录。然后把记录的字段变成对象属性而已。QeePHP 的 ActiveRecord 是很不同的,其属性不但可以是记录的字段,还可以映射到不同的方法。
举个最简单的例子:计算订单金额合计。
订单通常由多个订单项目组成,订单项目包含有商品的ID和购买价格。所以计算订单金额合计就是个遍历订单项目,然后用订单项目的价格乘以数量,最后累加。
// 传统的代码看上去类似这样
$sum = 0;
foreach ($order->items as $item) {
$sum += $item->price * $item->quantity;
}
虽然没什么问题,但是这段代码放在哪里合适呢?
放在控制器:业务逻辑跑到和用户界面打交道的地方去了
放在单独的函数中:还要传入订单对象,而且搞些全局函数,岂不是和面向对象的设计背道而驰,使用时还得载入单独的文件
放在一个公共类中:很好,这个类最后就会变成个大杂烩,什么都沾边
放在 Order 对象中:很不错,我们可以用 $order->getSum() 来获得订单金额合计。
与上面几种方法不同,QeePHP 的 ActiveRecord 可以这样做:
echo '订单金额合计:';
echo $order->sum;
我们数据库的 orders 表并没有 sum 这个字段,那这个属性怎么来的呢?
答案是 QeePHP 允许给 ActiveRecord 对象指定一些虚拟属性。这些属性并不实际存在。当访问对象这些虚拟属性时,QeePHP 会自动调用特定的方法来获取属性值。
所以订单的金额合计可以改成下面这样:
class Order extends QDB_ActiveRecord_Abstract
{
...... 定义 sum 属性对应到 getSum() 方法 ......
function getSum()
{
$sum = 0;
foreach ($this->items as $item) { $sum += $item->quantity * $item->price; }
return $sum
}
}
以后我们要获得订单金额不需要 $order->getSum(),只需要 $order->sum 接口。
同理,我们可以把 $item->quantity * $item->price 也给封装到订单项目对象中。
更进一步,除了属性的读取,属性的写入也可以对应到一个方法。
这样我们把订单项目的 quantity 和 price 属性分别指向 setQuantity() 和 setPrice() 方法。
这两个方法内部可以完成合法性检查(例如数量必须大于等于1,而价格不能是负数)。
以前这些判断方法要写在外部,现在都封装到对象内部了。
// 传统代码
$quantity = (int)$_POST['quantity'];
$price = (float)$_POST['price'];
if ($quantity 1) {
.... 报错
}
if ($price 0) {
... 报错
}
$order_item->quantity = $quantity;
$order_item->price = $price;
改进后的代码如下:
try {
// 假定 setQuantity() 和 setPrice() 方法会抛出异常
$order_item->quantity = (int)$_POST['quantity'];
$order_item->price = (int)$_POST['price'];
....
} catch (...) {
}
这个例子其实没什么实用价值,因为通常这些合计都是预先计算好就存在数据库里面了。
但这个例子很好的表现了如何更好的封装业务逻辑。
并且可以把一个很复杂的逻辑分散到各个对象中去实现,真正体现了面向对象的单一职责原则。
原文地址:
http://qeeify.com/index.php/2008/03/17/activerecord-properties-method.html
更多信息,请访问 FleaPHP/QeePHP 开源开发框架官方网站:
http://www.fleaphp.org/
。
相关阅读 更多 +
排行榜 更多 +