註:看不懂的請勿踩,此文章非針對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 表模組(不考慮)