《PHP设计模式介绍》第十六章 数据映射模式

80酷酷网    80kuku.com

  >

前两章――动态数据模式与表数据网关模式各自展示对记录与每个表进行抽象的策略。这些模式都很有用,但每一个模式的执行都与底层的数据库结构结合过于紧密,因此基于以上模式的解决方案就存在一定的问题。比如,你的代码用字段名作为数组的关键字或是行数据对象的属性,则你的应用就受到数据库结构的约束,并且每当表结构发生哪怕是很小的变化,你都不得不在你的PHP程序中做大量的修改。

因为代码与数据库结构在开发过程经常变更,甚至在部署后也会发生。将代码与其数据库尽可能的分离,隔绝二者间的相互依赖性并减少因某一方的变化而产生的修改工作是非常有益的。

问题

你怎样才能将你的应用类与所属的数据库之间的结合度降至最低?例如,当你的数据表字段名发生变化时,你怎样将与此相关的修改工作降至最低?

解决方案

数据映射模式将对象的属性与存储它们的表字段间的结合密度降低。数据映射模式的本质就是一个类,它映射或是翻译类的属性或是方法到数据库的相应字段,反之亦然。数据映射的作用(工作)就在于能对双方所呈现出的信息的理解,并能对信息的存取进行控制,如根据存储在数据表中的信息重建新的域对象,或是用域对象的信息来更新或删除数据表中的相关数据。

对于面向对象代码与数据库表和字段间的映射关系的存储有多种实现方式。其中一种可能的方法就通过手工编码将这种映射关系存储在数据映射类中。另一种可选的方法是用PHP的数组并将其编码为类本身。这个类也能外源获取数据,如INI或是XML文件。

下图展示了一个数据映射类图,该类应用于解决存储URL书签(在前两章里已应用到)这类问题域。在图中,Bookmark对象是域对象,BookmarkMapper是数据映射模式的一个实现(执行)。Bookmark应该包含业务逻辑如校验URLs。BookmarkMapper则完全是一个在Bookmark的getter与setter方法与bookmark表字段结构间的交叉参照物。

这两个为关系很密切:BookmarkMapper充当了一个工厂,来实例化Bookmark,并且接受

Bookmark类的实例作为很多BookmarkMapper操作的参数。

 


样本代码

用UML示图作为路标,让我们来实现Bookmark与BookmarkMapper类。

首先,正如上面所提及,需要某种配置文件来处理表字段与对象方法间的映射。在本例中,我们用XML作为配置文件。

这个配置的主要目的是列示Bookmark表的字段,并指定哪个方法用于从Bookmark对象中存储与获取各自的信息。一个非常简单的XML结构就足够了,由一个<bookmark>根元素与一系列的<field>元素构成,如下所示

<field>
<name>url</name>
<accessor>getUrl</accessor>
<mutator>setUrl</mutator>
</field>

<name>元素存储实际的物理字段名。<accessor>元素存储了获取属性数据方法的名称,它是可选项,因为一些字段如时间戳是不需要映射的。<mutaror>则存储了Bookmark类中完成填充对象值的方法名。另一些信息也能添加到这个映射表中,例如,你能声明每个字段的thetype 和size元素,这使得你能用这些信息动态的生成SQL来建立数据表。如果你的应用有一个用PHP写的安装包,则你会对此特别感兴趣,这样你就可以通过这个映射表来建立表结构。当设定基于以上信息的PHP对象属性时,你也能自动的设定其数据值。)

完整的XML文件如下:

<bookmark>
<field>
<name>id</name>
<accessor>getId</accessor>
<mutator>setId</mutator>
</field>
<field>
<name>url</name>
<accessor>getUrl</accessor>
<mutator>setUrl</mutator>
</field>
The Data Mapper Pattern 263
<field>
<name>name</name>
<accessor>getName</accessor>
<mutator>setName</mutator>
</field>
<field>
<name>description</name>
<accessor>getDesc</accessor>
<mutator>setDesc</mutator>
</field>
<field>
<name>tag</name>
<accessor>getGroup</accessor>
<mutator>setGroup</mutator>
</field>
<field>
<name>created</name>
<mutator>setCrtTime</mutator>
</field>
<field>
<name>updated</name>
<mutator>setModTime</mutator>
</field>
</bookmark>

可用PHP5中名为simpleXML的功能函数,来读取与解析这个文件。你所需要做的就是调用simplexml_load_file(‘bookmark.xml’),就生成了一个包含这个XML文件所有信息的SimpleXMLElement 对象集。这儿,结果看上去类似:

object(SimpleXMLElement)#21 (1) {
[“field”]=>
array(7) {
[0]=>
object(SimpleXMLElement)#15 (3) {
[“name”]=>
string(2) “id”
[“accessor”]=>
string(5) “getId”
[“mutator”]=>
string(5) “setId”
}
[1]=>
object(SimpleXMLElement)#19 (3) {
[“name”]=>
string(3) “url”
[“accessor”]=>
string(6) “getUrl”
[“mutator”]=>
string(6) “setUrl”
}
//...<snip>...
[4]=>
object(SimpleXMLElement)#23 (3) {
[“name”]=>
string(3) “tag”
[“accessor”]=>
string(8) “getGroup”
[“mutator”]=>
string(8) “setGroup”
}
//...<snip>...
}

因为此XML文件映射域空间到数据库空间,所以BookmarkMapper类在构造时会读取这个XML配置文件。在正式研究BookmarkMapper前,让我们深入研究一下Bookmark类。假设Bookmark已在已有的工程中使用,则对其修改带来的影响应是越小越好。此外,Bookmark不应该仅仅为了适应BookmarkMapper而修改。实际上,数据映射模式就是旨在亲和,域对象本身应对Data Mapper的存在保持完全的透明。(这里是意译)。

这又导致实现Data Mapper另一个重要的要求:因为Data Mappe对域对象透明,所有相关的对象都必须对所有相关的属性提供某种公共的通道,这样Data Mapper在建立时才能正确初始化域对象,并在保存域对象时可读取其属性值。

Bookmark的属性都是保护型的,但给每个属性提供了getter和setter方法,因此这正好能满足需求。

分享到
  • 微信分享
  • 新浪微博
  • QQ好友
  • QQ空间
点击: