← 回到文章

数据源架构模式之活动记录

数据源架构模式之活动记录 【活动记录的意图】 一个对象,它包装数据表或视图中某一行,封装数据库访问,并在这些数据上增加了领域逻辑。
【活动记录的适用场景】 适用于不太复杂的领域逻辑,如CRUD操作等。
【活动记录的运行机制】 对象既有数据又有行为。其使用最直接的方法,将数据访问逻辑置于领域对象中。 活动记录的本质是一个领域模型,这个领域模型中的类和基数据库中的记录结构应该完全匹配,类的每个域对应表的每一列。 一般来说,活动记录包括如下一些方法: 1、由数据行构造一个活动记录实例; 2、为将来对表的插入构造一个新的实例; 3、用静态查找方法来包装常用的SQL查询和返回活动记录; 4、更新数据库并将活动记录中的数据插入数据库; 5、获取或设置域; 6、实现部分业务逻辑。
【活动记录的优点和缺点】 优点: 1、简单,容易创建并且容易理解。 2、在使用事务脚本时,减少代码复制。 3、可以在改变数据库结构时不改变领域逻辑。 4、基于单个活动记录的派生和测试验证会很有效。
缺点: 1、没有隐藏关系数据库的存在。 2、仅当活动记录对象和数据库中表直接对应时,活动记录才会有效。 3、要求对象的设计和数据库的设计紧耦合,这使得项目中的进一步重构很困难
【活动记录与其它模式】 数据源架构模式之行数据入口:活动记录与行数据入口十分类似。二者的主要差别是行数据入口 仅有数据库访问而活动记录既有数据源逻辑又有领域逻辑。
【活动记录的PHP示例】
     */
    private $_order_id;

    /**
     * 客户ID
     * @var 
     */
    private $_customer_id;

    /**
     * 定单金额
     * @var 
     */
    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, " 
"; 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方法。
最后更新于 2010-10-17 22:56:21