注:看不懂的请勿踩,此文章非针对java,java爱好者可直接略过。
一、概念
行数据入口(Row Data Gateway):充当数据源中单条记录入口的对象,每行一个实例。
二、简单实现行数据入口
为了方便理解,还是先简单实现:
<?php
/**
* 行数据入口类
*/
class OrderGateway {
/*定义元数据映射*/
private $_name;
private $_id;
public function __construct($id, $name) {
$this->setId($id);
$this->setName($name);
}
public function getName() {
return $this->_name;
}
public function setName($name) {
$this->_name = $name;
}
public function getId() {
return $this->_id;
}
public function setId($id) {
$this->_id = $id;
}
/**
* 入口类自身拥有更新操作
*/
public function update() {
$data = array('id' => $this->_id, 'name' => $this->_name);
$sql = "UPDATE order SET ";
foreach ($data as $field => $value) {
$sql .= "`" . $field . "` = '" . $value . "',";
}
$sql = substr($sql, 0, -1);
$sql .= " WHERE id = " . $this->_id;
return DB::query($sql);
}
/**
* 入口类自身拥有插入操作
*/
public function insert() {
$data = array('name' => $this->_name);
$sql = "INSERT INTO order ";
$sql .= "(`" . implode("`,`", array_keys($data)) . "`)";
$sql .= " VALUES('" . implode("','", array_values($data)) . "')";
return DB::query($sql);
}
public static function load($rs) {
/* 此处可加上缓存 */
return new OrderGateway($rs['id'] ? $rs['id'] : NULL, $rs['name']);
}
}
/**
* 为了从数据库中读取信息,设置独立的OrderFinder娄。
*/
class OrderFinder {
public function find($id) {
$sql = "SELECT * FROM order WHERE id = " . $id;
$rs = DB::query($sql);
return OrderGateway::load($rs);//这里返回的行对象
}
public function findAll() {
$sql = "SELECT * FROM order";
$rs = DB::query($sql);
$result = array();
if (is_array($rs)) {
foreach ($rs as $row) {
$result[] = OrderGateway::load($row);
}
}
return $result;
}
}
class DB {
/**
* 这只是一个执行SQL的演示方法
* @param string $sql 需要执行的SQL
*/
public static function query($sql) {
echo "执行SQL: ", $sql, " <br />";
}
}
/**
* 客户端调用
*/
class Client {
public static function main() {
header("Content-type:text/html; charset=utf-8");
/* 写入示例 */
$data = array('name' => 'start');
$order = OrderGateway::load($data);
$order->insert();
/* 更新示例 */
$data = array('id' => 1, 'name' => 'stop');
$order = OrderGateway::load($data);
$order->setName('xxxxxx');
$order->update();
/* 查询示例 */
$finder = new OrderFinder();
$order = $finder->find(1);
echo $order->getName();
}
}
Client::main();
?>
三、运行机制
●行数据入口是单条记录极其相似的对象,在该对象中数据库中的每一列为一个域。
●行数据入口一般能实现从数据源类型到内存中类型的任意转换。
●行数据入口不存在任何领域逻辑,如果存在,则是活动记录。
●在实例可看到,为了从数据库中读取信息,设置独立的OrderFinder类。当然这里也可以选择不新建类,采用静态查找方法,但是它不支持需要为不同数据源提供不同查找方法的多态。因此这里最好单独设置查找方法的对象。
●行数据入口除了可以用于表外还可以用于视图。需要注意的是视图的更新操作。
●在代码中可见“定义元数据映射”,这是一种很好的作法,这样一来,所有的数据库访问代码都可以在自动建立过程中自动生成。
四、使用场景
4.1 事务脚本
可以很好地分离数据库访问代码,并且也很容易被不同的事务脚本重用。不过可能会发现业务逻辑在多处脚本中重复出现,这些逻辑可能在行数据入口中有用。不断移动这些逻辑会使行数据入口演变为活动记录,这样减少了业务逻辑的重复。
4.2 领域模型
如果要改变数据库的结构但不想改变领域逻辑,采用行数据入口是不错的选择。大多数情况,数据映射器更加适合领域模型。
行数据入口能和数据映射器一起配合使用,尽管这样看起来有点多此一举,不过,当行数据入口从元数据自动生成,而数据映射器由手动实现时,这种方法会很有效。
4.3 表模块(不考虑)