8

我一直在阅读多个PHP框架,特别是Zend框架,但我对正确的前进方向感到困惑。DataMapper模式是否打破MVC?

Zend Framework不使用ActiveRecords,而是使用Table Data Gateway和Row Data Gateway模式,并使用DataMapper将行数据网关的内容映射到模型,因为ActiveRecord在您的模型不与您的数据库表有1:1映射。 Zend Quickstart指南中有一个example of this

对我来说,他们的例子看起来非常臃肿,各地都有大量的getter和setter。我遇到过各种关于领域驱动设计的博客文章,他们认为使用如此多的getter和setter是不好的做法,因为它将所有内部模型数据公开给外部,所以它没有优于公共属性。 Here is one example

我的问题:如果你删除了这些getter和setters,你将如何渲染你的视图?在某些时候,数据必须显示在视图上,以便您可以向用户显示某些内容。遵循DDD的建议似乎打破了MVC中M和V之间的分离。遵循MVC和Zend的例子似乎打破了DDD,让我为我的所有模型输入了大量的getter,setters和DataMapper。除了做很多工作外,它似乎也违反了DRY。

我真的很感激一些(链接)好的例子或更多关于它如何融合在一起的信息。我试图在这里提高我的建筑和设计技能。

回答

2

使用Value Objects,可以消除一些公共setter方法。这里是对the difference between Entity and Value Objects的描述。值对象是不可变的,通常与实体关联。如果使用构造函数传递所有值,则不需要从外部代码设置这些属性。

额外的东西,不直接相关的答案,但更侧重于DDD:

(声明:我知道了Zend框架的唯一的事情是我所链接的文章中读出。)Zend框架使用DataMapper而不是存储库。这真的是DDD-ISH吗?那么,Fowler's interpretation of a Repository可能会说不。但是,埃里克埃文斯说,一个DDD仓库可以非常简单。最简单的说,存储库 DataMapper(见DDD书)。对于更复杂和仍然DDD的东西,请参阅福勒的文章。 DDD有一个可能与模式定义不同的概念性存储库。

我强烈建议您继续阅读关于领域驱动设计。我认为,假设吸收者和制定者违反DDD是有缺陷的。 DDD主要关注领域模型和最佳实践。访问者只是一个小细节。

+0

谢谢。那篇恶毒的文章能够很好的阅读。我还会读到系列的其余部分。 – 2009-06-24 08:14:38

+0

这是一个很好的答案,我会补充说,getters,setters有什么不对。事实上,拥有它们是增加验证逻辑的绝佳方式。公开物业是快速和肮脏的,可以在原型制作时使用,但不是一个很好的长期解决方案。假设你想改变一个属性的名字。如果你这样做,每一个访问该属性的代码都需要改变。如果您使用访问器方法的通用名称,则不必更改客户端代码。另外,Doctrine是比Zend DB更丰富的解决方案。我不会推荐Doctrine1,但是请尝试Doctrine2。 – 2010-08-20 08:26:49

2

你不需要实现所有的getter/setter,你可以使用_get()和__set()。那么问题是什么?

1

从我阅读帖子来看,这个问题更具哲理性而非实用性。

我没有时间写深入,但这里是我的两美分。虽然我同意你想限制get和set请求的数量,因为一个类应该隐藏它的内部,但你也需要考虑到Java和PHP是不同的工具并且有不同的目的。在Web环境中,每个请求都会构建和取下类,因此您编写的代码不应依赖于大型类。在你指出的文章中,作者建议将视图逻辑放在类中。这可能在网络上没有意义,因为我可能想要以多种格式(rss,html等)呈现视图。因此使用访问器方法(获取&集)是一个必要的罪恶。你仍然想要好好地使用它们,这样你就不会在脚下开枪。关键是要让你的班级为你做好工作,而不是试图迫使他们在外面做工作。通过用方法而不是直接访问你的属性,你可以隐藏你想要的内部。

再次,这篇文章可以使用一些例子,但我现在没有时间。

其他人可以提供一些为什么accessor方法不邪恶的例子吗?

+0

谢谢。我的问题确实比实际更具哲理性。将视图逻辑放在域模型中对我来说似乎有问题(因为它违反了MVC),这就是问题的原因。我真正希望看到的是一些实际例子,清楚地表明理论在实践中。如果它确实是域驱动设计和MVC之间的平衡,那么我很想看看其他人如何解决它们之间的明显冲突。 – 2009-06-22 22:40:38

0

实现getter和setter方法有两个好处,在我的眼前:

  1. 你可以选择属性,使公众,所以你不必去揭露所有的模型内部的
  2. 如果您使用带有自动完成功能的IDE,当你开始输入“get”或“set”时,所有可用的属性都会被TAB带走 - 这对我来说已经足够了。
1

这里有两种方法:我称之为“告诉不问问题的方法”,另一种方法是ViewModel/DTO方法。 本质上,问题围绕着你的观点中的“模型”展开。 告诉别问,要求对象可以被外化的唯一方式是来自对象本身。换句话说,为了渲染一个对象,你需要一个渲染方法,但是这个渲染方法需要与一个接口进行通信。 事情是这样的:

class DomainObject { 
    .... 
    public function render(DomainObjectRenderer $renderer) { 
     return $renderer->renderDomainObject(array $thegorydetails); 
    } 
} 

在Zend框架的情况下,你也可以继承的Zend_View和你的子类实现此接口。

我以前做过这个,但它有点笨拙。

第二种选择是将您的域模型转换为ViewModel对象,它类似于为每个特定视图(每个视图使用一个ViewModel)自定义的数据的简化,展平,“放大”视图,以及在回来的路上,将POST数据转换为EditModel。

这是ASP.NET MVC世界中非常流行的模式,但它也类似于用于在应用程序中的“图层”之间传输数据的类“DTO”模式。您需要创建映射器来为您执行肮脏的工作(与DataMapper实际上不同)。在PHP 5.3中,你可以使用反射来改变私有属性,所以你的DomainObject甚至不需要暴露自己!