RSS
热门关键字:  php  lighttpd  找回密码  密码找回  client
当前位置 :| 主页>技术资料>PHP>

如何运用连贯接口3

来源: 作者: 时间:2008-08-19 Tag: 点击:

用连贯接口实现 DSL 风格编程

上一篇:如何运用连贯接口2

转自:http://www.fleaphp.org/index.php?q=node/68

DSL 是一个比较热门的概念,是领域描述语言(Domain Specific language)的英文缩写。不过这里我不想和大家解释概念问题,这个任务还是留给其他人吧 :)

从实践来说,DSL 风格就是通过一组前后关联的方法调用来完成一个领域操作。所谓领域操作可以看作常说的业务操作,虽然本质上两个定义是不同的。

下面就是一段创建订单的代码:

// 通过 SESSION 获得当前用户对象,然后创建一个新的 Order 对象
$order = $session->getCurrentUser()->newOrder()
// 添加产品和数量信息到订单中
$order->addItem(Product::find('id=?', intval($_POST['product_id'])))
      ->withQuantity(intval($_POST['quantity']);
// 保存订单对象
$order->save();看看内部实现的主要代码:

/**
 * Member 封装一个用户
 */
class Member extends QActiveRecord_Abstract
{
    function newOrder()
    {
        // 构造订单对象要求传入用户ID
        $order = new Order($this);
        // 根据用户的属性,设置订单的折扣率、收货人等信息
        $order->withDiscount($this->purchaseDiscount)
              ->withConsignee($this->realname)
              ->withAddress($this->address)
    }
}

/**
 * Order 封装一个订单
 */
class Order extends QActiveRecord_Abstract
{
    /**
     * 下订单的用户
     *
     * @var Member
     */
    protected $_user;

    /**
     * 保存订单的多个项目
     *
     * @var array
     */
    protected $_items;

    /**
     * 收货地址
     *
     * @var Address
     */
    protected $_address;

    function __construct(Member $user)
    {
        $this->_user = $user;
    }

    /**
     * 设置订单的折扣率
     *
     * @param float $discount
     *
     * @return Order
     */
    function withDiscount($discount)
    {
        // 设置订单的折扣率
        $this->discount = $discount;
        return $this;
    }

    /**
     * 设置订单的收货地址
     *
     * @param Address $address
     *
     * @return Order
     */
    function withAddress(Address $address)
    {
        $this->address = $address;
        return $this;
    }

    /**
     * 添加一个购买项目
     *
     * @param Product $product
     * @param int $quantity
     *
     * @return OrderItem
     */
    function addItem(Product $product, $quantity = 1)
    {
        // 添加一个订单项目
        $item = new OrderItem($product);
        $item->withQuantity($quantity);
        $this->items[] = $item;
        return $item;
    }

    /**
     * sum 属性的 getter 方法
     *
     * @return float
     */
    function getSum()
    {
        $sum = 0;
        foreach ($this->_items as $item) {
            /* @var $item OrderItem */
            $sum += $item->sum;
        }
        return $sum;
    }
}

/**
 * OrderItem 封装一个订单项目
 */
class OrderItem extends QActiveRecord_Abstract
{
    /**
     * 订单项目对应的商品
     *
     * @var Product
     */
    protected $_product;

    /**
     * 订单项目金额合计
     *
     * @var float
     */
    protected $_sum;

    /**
     * 购买数量
     *
     * @var int
     */
    protected $_quantity;

    function __construct(Product $product)
    {
        $this->_product = $product;
    }

    /**
     * 指定购买数量
     *
     * @param int $quantity
     *
     * @return OrderItem
     */
    function withQuantity($quantity)
    {
        $this->_quantity = $quantity;
        $this->_sum = $this->_product->price * $this->_quantity;
        return $this;
    }

    /**
     * sum 属性的 getter 方法
     *
     * @return float
     */
    function getSum()
    {
        return $this->_sum;
    }
}
在这个示例中,我们用到多个对象。这些对象,每一个都只承担了属于自己的那部分职责。这种设计,使得整个对象体系清晰可见,对于功能的扩展和修改都提供了帮助。

当然,这几个类都从 QActiveRecord_Abstract 继承。正是 QActiveRecord_Abstract 封装了对只读属性、属性方法以及对象的 CRUD 等操作,才使得我们可以将精力集中于编写业务代码。

结束语

连贯接口是一种非常有价值的语法工具,在特定场合可以简化编码和提高代码的可读性。但是正如所有技术和概念,连贯接口也有自己适合的领域。超出这个领域,再强行使用连贯接口就事倍功半了 ;)

限于个人水平,本文难免存在不足和错误。希望能够听到广大 PHPer 的反馈意见,这样对于所有人来说都是一个学习提高的过程。


最新评论共有 0 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?
注册