三篇文章帮你理解Repository设计模式和运用.
我刚开始接触symfony的时候,觉得entity, repo类似zend framework里面的model和mapper的关系。 model是数据模型, mapper是操作数据模型。 显然这种理解是肤浅的。
Entity和Repo的概念是在DDD里面提出来的。详细的说明推荐阅读:殷浩详解DDD系列 第三讲 – Repository模式。 在这篇文章中,剖析Repo的本质比较透彻。他用的是Java世界的实现。在PHP世界,特别是Symfon框架内,与之相比又有一些比较特殊的地方。
Repo是一种规范,用来隔离Entity(实体,领域内的模型)和DO(数据模型,持久层的数据模型)。
1. Repo的使用“中性”的动词,而不该使用数据持久层的专用动词, 比如避免使用 select, insert, , update, delete这样的动词作为方法名。
2. Repo是服务于Entity的,同时自身不该直接操作DO(比如数据库)。 所以推荐动词find
、save
、remove
来作为方法名
在接触这些信息之前,我曾经在DH项目里自己实现过对DDD的理解。当时我理解的领域内的模型,就类似一个需要同时修改多个数据表的模型。
在这篇文章中, 作者在symfony框架中如何使用Repo 发表了见解。 首先,他否定了symfony文档中的范例。在这个范例中,文档作者在controller里面通过继承获得的doctrie对象来获取entity manager, 然后用它创建Repo对象。作者说只有初学者才会在实际工作中使用这种方法,因为依赖被写死了。他建议使用service.
写一个repo service, 让controller只依赖这个service. 在这个service里,通过注入repo对象。然后repo对象也不要使用继承获得的findAll等方法,而只使用自家的方法。 作者称为“use composition instead of inheritance“. 所以需要写一个repo的interface,然后把自家的方法都在这个interface内定义好。这样写的好处是,脱耦。
结果调用关系就从
controller -> doctrine -> manager -> repo -> doctrine
变为了
controller-> service -> repo -> doctrine
这样的写的好处就是分层了。
在这篇文章内,不直接使用doctrine,而使用service,称为放弃 Service Locator Pattern ( 设计模式)而是使用 Dependcy injection (依赖注入模式)
不直接使用继承获得的方法,而是调用自己的方法叫做避免违反 Low of demeter 迪米特法则 (介绍)
分层好处的体现:
测试容易了。由于每一层只调用自己的下一层,所以mock起来特别方便。 要测试conterller只需要模拟一个service. 要测试service只需要模拟一个repo. 测试repo只需要模拟一个doctrine。避免了复杂的依赖关系
扩展容易了。比如如果需要在每次保存对象后触发一个事件,那么只要扩展service层就可以了。这样controller可以一直保持苗条。
Repository Pattern
Repository Pattern in Symfony
Doctrine Repositories should be collections without flush