我在我正在开发的PHP应用程序中使用数据映射器模式并且有一个问题。目前,您请求具有特定ID的Site对象,映射器将查找该行,创建对象并将其返回。但是,如果对同一站点再次执行此操作,则最终会得到两个具有相同数据的不同对象。例如:
$mapper = new Site_Mapper();
$a = $mapper->get(1);
$b = $mapper->get(1);
$a == $b // true
$a === $b // false
所以,我的问题是,我应该:
答案 0 :(得分:5)
您正在寻找的是身份地图模式。但要注意所谓的“阅读不一致”。使用“旧实例”时,数据库可能已经更改。在编辑对象时,另一个用户可能会获得它的实例,更快地更改它并更快地保存它。然后另一个对象再次覆盖所有这些更改。在网络上虽然可能不是一个大问题,因为“页面”很快就会通过并且没有任何对象存活超过几秒钟。
答案 1 :(得分:2)
我知道很久以前问过这个问题仍然想要回答,以防其他人遇到类似的困境。实际上,作者提出的上述建议#1,2,3都是相关的,为了解决这个问题,应该考虑所有这些建议。
1)将从DB对象检索到的每个对象存储在映射器中,以便在请求具有相同ID的对象时不必再次执行此操作。在所有后续调用中,映射器应返回存储的对象。这称为 IdentityMap 模式。要实现此目的,请在映射器中创建一个私有属性,以保存给定对象类型的IdentityMap实例。 Site_Mapper-> get()方法应该始终检查IdentityMap是否有给定ID,如果没有检索到该对象,则映射器将转到数据库,但如果它已经存储在地图中,它将返回保存行程的缓存实例数据库。那么$ a === $ b应该是真的,因为它们将引用同一个对象实例。
2)理想情况下,应始终有给定数据映射器(Site_Mapper)的一个实例,以便在给定时间维护IdentityMap的单个实例。这可以使用 Singleton 模式完成。这可以通过一些getter方法实现,例如 Site_Mapper :: getInstance(),它将始终返回给定映射器的相同实例。您还必须将 __ construct()声明为私有方法,以防止使用 new 进行不必要的实例化,并确保 getInstance()是实例化映射器的唯一方法。
3)作者上面提到的关于静态属性的内容也是正确的。要在PHP中实现 Singleton ,必须使用静态属性来保存Mapper的实例。
我强烈推荐Martin Fowler的书“企业应用程序架构模式”,其中讨论了上述模式等等。这是一个很好的阅读,特别是如果你正在使用自己的自定义ORM解决方案。希望有所帮助。
答案 2 :(得分:1)
我会以某种方式使用缓存 - 静态映射器类将是我的第一选择,并且是我最常见的。否则,您的选项2(单身模式)可能是最佳选择。
请记住,在进行更新时需要清除此缓存以避免返回过时数据。
话虽如此,除非你想要大量使用或者做很多查询,否则可能并不重要。 (你的4)
另外值得寻找指导(我确定有很多例子,我只知道这个最好),Propel(http://propel.phpdb.org/)有缓存功能 - 可能值得看看它是如何做到的?或者只是使用它?