Scala 中的 DAO 模式已经过时了吗?
让我们考虑一个 DAO 模式的简单示例。令 Person
是一个值对象,而 PersonDAO
是对应的特征,它提供了将 Person
存储到数据库或从数据库检索 Person
的方法。
trait PersonDAO { def create(p:Person) def find(id:Int) def update(p:Person) def delete(id:Int) }
如果我们想要分离业务域和持久性逻辑,我们可以使用此模式(例如,与 Active Record 相反) 。
如果我们使用另一种方法呢? 我们将创建PersonDatabaseAdapter
trait PersonDatabaseAdapter{ def create def retrieve(id:Int) def update def delete }
以及从 Person
到它的隐式转换。
implicit def toDatabaseAdapter(person:Person) = new PersonDatabaseAdapter { def create = ... def retrieve(id:Int) = ... def update = ... def delete = ... }
现在,如果我们导入这些转换,我们可以编写客户端代码来操作 Persons
并通过以下方式将它们存储到数据库或从数据库检索它们:
val person1 = new Person ... person1.create ... val person2 = new Person ... person2.retrieve(id) ...
此代码看起来像 Active Record
但业务领域和持久化仍然是分离的。
有道理吗?
Let's consider a simple example of DAO pattern. Let Person
is a value object and PersonDAO
is the correspondent trait, which provides methods to store/retrieve Person
to/from the database.
trait PersonDAO { def create(p:Person) def find(id:Int) def update(p:Person) def delete(id:Int) }
We use this pattern (as opposed to Active Record, for example), if we want to separate the business domain and persistence logic.
What if we use another approach instead ?
We will create PersonDatabaseAdapter
trait PersonDatabaseAdapter{ def create def retrieve(id:Int) def update def delete }
and implicit conversion from Person
to it.
implicit def toDatabaseAdapter(person:Person) = new PersonDatabaseAdapter { def create = ... def retrieve(id:Int) = ... def update = ... def delete = ... }
Now if we import these conversions, we can write client code to manipulate Persons
and store/retrieve them to/from the database in the following manner:
val person1 = new Person ... person1.create ... val person2 = new Person ... person2.retrieve(id) ...
This code looks like Active Record
but the business domain and persistence are still separated.
Does it make sense ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
好吧,我对“过时”模式一无所知。模式就是模式,您可以在适当的地方使用它。另外,我不知道任何模式在语言中是否应该被废弃,除非语言本身使用相同的功能实现它。
据我所知,数据访问对象并没有过时:
http://java.sun.com/blueprints/corej2eepatterns/ Patterns/DataAccessObject.html
http://en.wikipedia.org/wiki/Data_access_object
Well, I don't know anything about "obsolete" patters. Pattern is a pattern and you use it where appropriate. Also, I don't know if any pattern should be obsolete in a language unless language itself implements it with the same functionality.
Data access object is not obsolete to my knowledge:
http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html
http://en.wikipedia.org/wiki/Data_access_object
在我看来,您仍在使用 DAO 模式。您只是以不同的方式实现了它。
我实际上发现这个问题是因为我正在研究 DAO 模式在普通的 Java 中是否已经死亡,考虑到 Hibernate 的强大功能。看起来 Hibernate Session 是 DAO 的通用实现,定义了诸如创建、保存、saveOrUpdate 等操作。
在实践中,我发现使用 DAO 模式没有什么价值。使用 Hibernate 时,DAO 接口和实现是单行 Hibernate Session 习惯用法的冗余包装,例如 getSession().update(...);
您最终得到的是重复的接口 - 一个服务接口,它重新定义了 DAO 接口中的所有方法以及根据这些方法实现的其他一些方法。
看起来 Spring + Hibernate 几乎将持久逻辑简化到了微不足道的程度。几乎所有应用程序都不需要持久性技术的可移植性。 Hibernate 已经为您提供了数据库可移植性。当然,DAO 会让您能够从 Hibernate 更改为 Toplink,但实际上,人们永远不会这样做。持久性技术已经是有漏洞的抽象,并且应用程序是为了处理这个事实而构建的 - 例如加载代理来设置关联与执行数据库命中 - 这必然将它们与持久性技术结合起来。不过,与 Hibernate 耦合并不是那么糟糕,因为它会尽力摆脱干扰(没有像 JDBC 那样的检查异常和其他废话)。
总之,我认为 DAO 模式的 Scala 实现很好,尽管您可能可以创建一个完全通用的 mixin,为任何实体提供基本的 CRUD 操作(大多数有能力的开发人员倾向于在 Java 中实现“通用 DAO”基类) , 也)。这就是 Active Record 的作用吗?
/随机评论结束/
It seems to me that you are still using the DAO pattern. You have just implemented it differently.
I actually found this question because I was researching whether the DAO pattern is dead in plain ol' Java, given the power of Hibernate. It seems like the Hibernate Session is a generic implementation of a DAO, defining operations such as create, save, saveOrUpdate, and more.
In practice, I have seen little value in using the DAO pattern. When using Hibernate, the DAO interfaces and implementations are redundant wrappers around one-liner Hibernate Session idioms, e.g., getSession().update(...);
What you end up with is duplicate interfaces - a Service interface that redefines all of the methods in the DAO interface plus a few others implemented in terms of those.
It seems that Spring + Hibernate has reduced persistence logic almost to a triviality. Persistence technology portability is NOT needed in almost all applications. Hibernate already gives you database portability. Sure, DAOs would give you the ability to change from Hibernate to Toplink, but in practice, one would never do this. Persistence technologies are already leaky abstractions and applications are built to deal with this fact - such as loading a proxy for setting associations vs. performing a database hit - which necessarily couples them to the persistence technology. Being coupled to Hibernate is not really so bad though since it does its best to get out of the way (no checked exceptions a la JDBC and other nonsense).
In summary, I think that your Scala implementation of the DAO pattern is fine, though you could probably create a completely generic mixin that would give basic CRUD operations to any entity (most competent devs tend to implement a "generic DAO" base class in Java, too). Is that what Active Record does?
/end of random comments/
我相信您的
PersonDatabaseAdapter
在其retrieve(id: Int)
方法中改变了Person
。因此,这种模式迫使您的域对象是可变的,而 Scala 社区似乎由于语言的功能性质(或特性)而倾向于不变性。除此之外,我认为 DAO 模式在 Scala 中仍然具有相同的优点和缺点(在此处列出):在 Java 中也是如此。
I believe your
PersonDatabaseAdapter
mutatesPerson
in itsretrieve(id: Int)
method. So this pattern forces your domain objects to be mutable, while the Scala community seems to favor immutability due to the functional nature (or features) of the language.Otherwise, I think the DAO pattern still has the same advantages and disadvantages (listed here) in Scala as it does in Java.
如今,我注意到存储库模式非常流行,特别是因为它的术语使您看起来像是在处理集合。
Nowadays I notice the Repository pattern to be quite popular especially as its terminology makes it look like you're dealing with collections.