好的,我读了很多关于存储库模式的内容,包括Fowler的书。 我知道它是什么以及它做了什么,但是我还不确定它是如何被工厂和/或域对象调用的。
我理解的是,存储库应该像域对象的内存中集合一样,而工厂是负责实例创建的类:new myDomainObject()
考虑到这一点,很明显存储库需要引用工厂来从数据源查询创建新对象。 (存储库 - >工厂)
域对象还需要对工厂的引用才能创建新对象。
我的困境是当域对象想要检索现有对象时,它应该调用存储库还是工厂? 如果它直接调用存储库(Domain - > Repository - > Factory),那么它需要同时拥有对工厂和存储库的引用,这对我来说似乎太过分了,但它是不是很糟糕?
另一方面,如果它像factory.CreateObjectWithId(id)
那样调用工厂,那么工厂必须只将调用重定向到存储库repository.GetById(id)
,最后这个调用将在同一个工厂调用另一个方法用于创建对象(如果它尚未在内存中)factory.CreateObject(dataset)
,因此导致循环引用:
域对象 - >工厂< - >存储库,这对我来说似乎不是一件好事。
那么在您看来哪些选项更好?或者还有其他选择吗?
答案 0 :(得分:5)
你已经掌握了基础知识。 您的误解似乎来自于您假设域对象应该是存储库的主要客户端。不是这种情况,如果没有其他方法,您应该只从域对象访问存储库。尽量避免使用它。
因此,等式中缺失的部分是作为存储库的主要客户端的东西。
应用程序服务是一种包含用例逻辑的服务(与域逻辑相对)。它执行输入验证,实现访问管理,并负责事务控制。
这意味着应用服务将使用存储库从数据库加载聚合,对其执行某些操作,然后确保更改是持久的(即提交事务)。
根据您使用的存储库样式,将聚合保存回数据库略有不同:
关于您关于工厂和存储库之间关系的问题,我认为this answer of mine也提供了您的问题的答案。它的基本要点是:
如果您经常需要从数据库中查询其他聚合以在域层中执行业务任务,则表明您的聚合边界可能是错误的。
当然,有些情况下聚合边界很好,并且所需的对象不能作为参数传递给域对象。在这种情况下,使用域中的存储库是有意义的。在执行此操作之前,请务必尝试其他方法。在任何情况下,只依赖于存储库接口,从不在具体的存储库实现上。