登录  /  注册
数据源架构模式之数据映射器
巴扎黑
发布: 2016-11-12 10:43:43
原创
719人浏览过

前面分别介绍了数据源架构模式之表数据入口、数据源架构模式之行和数据入口数据源架构模式之活动记录,相较于这三种数据源架构模式,数据映射器显得更加“高大上”。

一、概念

数据映射器(Data Mapper):在保持对象和数据库(以及映射器本身)彼此独立的情况下,在二者之间移动数据的一个映射器层。概念永远都是抽象的,简单的说,数据映射器就是一个负责将数据映射到对象的类数据。

二、为什么要使用数据映射器?

数据映射器实现起来比前三种模式都要复杂,那为什么还要使用它呢?

对象间的组织关系和关系数据库中的表是不同的。数据库表可以看成是由行与列组成的格子,表中的一行可以通过外键和另一个表(甚至同一个表)中的一行关联,而对象的组织关系更为复杂:一个对象可能包含其他对象;不同的数据结构可能通过不同的方式组织相同的对象。

对象和关系数据库之间的这种分歧被称为“对象关系阻抗不匹配”或“阻抗不匹配”。

数据映射器可以很好地解决这个问题,由它来负责对象和关系数据库两者数据的转换,从而有效地在领域模型中隐藏数据库操作并管理数据库转换中不可以避免的冲突。

三、简单实现数据映射器

Php代码

<?php  
//领域抽象类  
abstract class DomainObject {  
    private $id = -1;  
  
    function __construct( $id=null ) {  
        if ( is_null( $id ) ) {  
            $this->markNew();  
        } else {  
            $this->id = $id;  
        }  
    }  
  
    function getId( ) {  
        return $this->id;  
    }  
  
    static function getCollection( $type ) {  
        //这里通过一个工广生成此对象对应的数组数据对象  
        return HelperFactory::getCollection( $type );   
    }  
   
    function collection() {  
        return self::getCollection( get_class( $this ) );  
    }  
  
    function finder() {  
        return self::getFinder( get_class( $this ) );  
    }  
  
    static function getFinder( $type ) {  
        //这里通过一个工厂生成此对象对应的map对象  
        return HelperFactory::getFinder( $type );   
    }  
  
    function setId( $id ) {  
        $this->id = $id;  
    }  
  
    function __clone() {  
        $this->id = -1;  
    }  
}  
  
//场所类  
class Venue extends DomainObject {  
    private $name;  
    private $spaces;  
  
    function __construct( $id=null, $name=null ) {  
        $this->name = $name;  
        parent::__construct( $id );  
    }  
      
    function setSpaces( SpaceCollection $spaces ) {  
        $this->spaces = $spaces;  
    }   
  
    function getSpaces() {  
        if ( ! isset( $this->spaces ) ) {  
            //创建对应的SpaceMapper对象  
            $finder = self::getFinder( 'Space' );   
            $this->spaces = $finder->findByVenue( $this->getId() );  
            //$this->spaces = self::getCollection("Space");  
        }  
        return $this->spaces;  
    }   
  
    function addSpace( Space $space ) {  
        $this->getSpaces()->add( $space );  
        $space->setVenue( $this );  
    }  
  
    function setName( $name_s ) {  
        $this->name = $name_s;  
    }  
  
    function getName( ) {  
        return $this->name;  
    }  
      
    static function findAll() {  
        $finder = self::getFinder( __CLASS__ );   
        return $finder->findAll();  
    }  
    static function find( $id ) {  
        $finder = self::getFinder( __CLASS__ );   
        return $finder->find( $id );  
    }  
  
}  
  
  
abstract class Mapper{  
    protected static $PDO;   
    function __construct() {  
   
        if ( ! isset(self::$PDO) ) {   
            //此处可加缓存  
            self::$PDO = new PDO( $dsn );  
            self::$PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  
        }  
    }  
  
    private function getFromMap( $id ) {  
        //从内存取出此$id的DomainObject对象  
    }  
  
    private function addToMap( DomainObject $obj ) {  
        //将此DomainObject对象加入到内存  
    }  
  
    function find( $id ) {  
        $old = $this->getFromMap( $id );  
        if ( $old ) { return $old; }  
        $this->selectstmt()->execute( array( $id ) );  
        $array = $this->selectstmt()->fetch( );   
        $this->selectstmt()->closeCursor( );  
        if ( ! is_array( $array ) ) { return null; }  
        if ( ! isset( $array['id'] ) ) { return null; }  
        $object = $this->createObject( $array );  
        return $object;   
    }  
  
    function findAll( ) {  
        $this->selectAllStmt()->execute( array() );  
        return $this->getCollection( $this->selectAllStmt()->fetchAll( PDO::FETCH_ASSOC ) );  
    }  
   
    function createObject( $array ) {  
        $old = $this->getFromMap( $array['id']);  
        if ( $old ) { return $old; }  
        $obj = $this->doCreateObject( $array );  
        $this->addToMap( $obj );  
        return $obj;  
    }  
  
    function insert( DomainObject $obj ) {  
        $this->doInsert( $obj );   
        $this->addToMap( $obj );  
    }  
  
    protected abstract function getCollection( array $raw );  
    protected abstract function doCreateObject( array $array );  
    protected abstract function doInsert( DomainObject $object );  
    protected abstract function targetClass();  
    protected abstract function selectStmt( );  
    protected abstract function selectAllStmt( );  
}  
  
class VenueMapper extends Mapper {  
  
    function __construct() {  
        parent::__construct();  
        $this->selectAllStmt = self::$PDO->prepare(   
                            "SELECT * FROM venue");  
        $this->selectStmt = self::$PDO->prepare(   
                            "SELECT * FROM venue WHERE id=?");  
        $this->updateStmt = self::$PDO->prepare(   
                            "UPDATE venue SET name=?, id=? WHERE id=?");  
        $this->insertStmt = self::$PDO->prepare(   
                            "INSERT into venue ( name )   
                             values( ? )");  
    }   
      
    function getCollection( array $raw ) {  
        //这里简单起见用个对象数组  
        $ret = array();  
        foreach ($raw as $value) {  
            $ret[] = $this->createObject($value);  
        }  
        return $ret;  
    }  
  
    protected function doCreateObject( array $array ) {  
        $obj = new Venue( $array['id'] );  
        $obj->setname( $array['name'] );  
        //$space_mapper = new SpaceMapper();  
        //$space_collection = $space_mapper->findByVenue( $array['id'] );  
        //$obj->setSpaces( $space_collection );  
        return $obj;  
    }  
  
    protected function targetClass() {  
        return "Venue";  
    }  
  
    protected function doInsert( DomainObject $object ) {  
        $values = array( $object->getname() );   
        $this->insertStmt->execute( $values );  
        $id = self::$PDO->lastInsertId();  
        $object->setId( $id );  
    }  
      
    function update( DomainObject $object ) {  
        $values = array( $object->getname(), $object->getid(), $object->getId() );   
        $this->updateStmt->execute( $values );  
    }  
  
    function selectStmt() {  
        return $this->selectStmt;  
    }  
  
    function selectAllStmt() {  
        return $this->selectAllStmt;  
    }  
  
}  
  
//client代码  
  
$venue = new venue();  
$venue->setName("XXXXXXX");  
//插入一条数据  
$mapper = new VenueMapper();  
$mapper->insert($venue);  
//获取刚插入的数据  
$venueInfo = $mapper->find($venue->getId());  
//修改数据   
$venue->setName('OOOOOOOOOOO');  
$mapper->update($venue);  
?>
登录后复制

代码省略了一些辅助类,保留最主要的领域对象和数据映射器。数据映射器模式最强大的地方在于消除了领域层和数据库操作之间的耦合。Mapper对象在幕后运作,可以应用于各种对象关系映射。而与之带来的是需要创建大量具体的映射器类。不过现在框架都可以通过程序自动生成了。

四、使用时机

使用数据库映射器的主要是数据库方案和对象模型需要彼此独立演变的时候。最常见的当然是和领域模式一起使用。数据映射器无论是在设计阶段、开发阶段,还是测试阶段,在领域模型上操作时可以不考虑数据库。领域对象对数据库的结构一无所知,因为所有这些对应关系都由数据映射器完成。

当然,数据映射器引入了新的层次,因此使用这些模式的前提条件是业务逻辑的复杂性,如果很简单,那就没必要了。

如果没有领域模型,我不会选用数据映射器。但是没有数据映射器时,能使用领域模型吗?如果领域模型简单,且数据库受领域模型开发者的控制,则领域对象用活动记录直接访问数据库也是合理的。

不必创建完全意义上的数据库映射层。创建这样的数据映射器很复杂。大多数情况下,建议使用开源的数据库映射层而不是自己动手创建


来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 技术文章
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2023 //m.sbmmt.com/ All Rights Reserved | 苏州跃动光标网络科技有限公司 | 苏ICP备2020058653号-1

 | 本站CDN由 数掘科技 提供

登录PHP中文网,和优秀的人一起学习!
全站2000+教程免费学