QeePHP使用ActiveRecord更好的封装业务逻辑
通常的 ActiveRecord 实现,无非是封装一个数据库记录。然后把记录的字段变成对象属性而已。QeePHP 的 ActiveRecord 是很不同的,其属性不但可以是记录的字段,还可以映射到不同的方法。
举个最简单的例子:计算订单总金额
订单通常由多个订单项目组成,订单项目包含有商品的ID和购买价格。所以计算订单金额合计就是遍历订单项目,然后用订单项目的价格乘以数量,最后累加。
//传统代码
放在控制器:业务逻辑跑到和用户界面打交道的地方去了
放在单独的函数中:还要传入订单对象,而且搞些全局函数,岂不是和面向对象的设计背道而驰,使用时还得载入单独的文件
放在一个公共类中:很好,这个类最后就会变成个大杂烩,什么都沾边
放在 Order 对象中:很不错,我们可以用 $order->getSum() 来获得订单金额合计。
与上面几种方法不同,QeePHP 的 ActiveRecord 可以这样做:
答案是 QeePHP 允许给 ActiveRecord 对象指定一些虚拟属性。这些属性并不实际存在。当访问对象这些虚拟属性时,QeePHP会自动调用特定的方法来获取属性值。所以订单的金额合计可以改成下面这样:
但这个例子很好的表现了如何更好的封装业务逻辑。
并且可以把一个很复杂的逻辑分散到各个对象中去实现,真正体现了面向对象的单一职责原则。
举个最简单的例子:计算订单总金额
订单通常由多个订单项目组成,订单项目包含有商品的ID和购买价格。所以计算订单金额合计就是遍历订单项目,然后用订单项目的价格乘以数量,最后累加。
//传统代码
<?php $sum = 0; foreach ($order->items as $item) { $sum += $item->price * $item->quantity; }虽然没什么问题,但是这段代码放在哪里合适呢?
放在控制器:业务逻辑跑到和用户界面打交道的地方去了
放在单独的函数中:还要传入订单对象,而且搞些全局函数,岂不是和面向对象的设计背道而驰,使用时还得载入单独的文件
放在一个公共类中:很好,这个类最后就会变成个大杂烩,什么都沾边
放在 Order 对象中:很不错,我们可以用 $order->getSum() 来获得订单金额合计。
与上面几种方法不同,QeePHP 的 ActiveRecord 可以这样做:
<?php echo '订单金额合计:'; echo order->sum;我们数据库的 orders 表并没有 sum 这个字段,那这个属性怎么来的呢?
答案是 QeePHP 允许给 ActiveRecord 对象指定一些虚拟属性。这些属性并不实际存在。当访问对象这些虚拟属性时,QeePHP会自动调用特定的方法来获取属性值。所以订单的金额合计可以改成下面这样:
<?php 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,而价格不能是负数)。以前这些判断方法要写在外部,现在都封装到对象内部了。
// 传统代码 <?php $quantity = (int)$_POST['quantity']; $price = (float)$_POST['price'];if ($quantity < 1) { //... 报错 } if ($price < 0) { //... 报错 } $order_item->quantity = $quantity; $order_item->price = $price;//改进代码:
<?php try { // 假定 setQuantity() 和 setPrice() 方法会抛出异常 $order_item->quantity = (int)$_POST['quantity']; $order_item->price = (int)$_POST['price']; .... } catch (Exception $e) { //..... }这个例子其实没什么实用价值,因为通常这些合计都是预先计算好就存在数据库里面了。
但这个例子很好的表现了如何更好的封装业务逻辑。
并且可以把一个很复杂的逻辑分散到各个对象中去实现,真正体现了面向对象的单一职责原则。
版权声明:除非注明,本文由( blogdaren )原创,转载请保留文章出处。
发表评论: