Spring与贫血域模型
因此,我注意到我确实有一种倾向,我的Spring/Hibernate堆栈对象的模式如下:Spring与贫血域模型,spring,oop,Spring,Oop,因此,我注意到我确实有一种倾向,我的Spring/Hibernate堆栈对象的模式如下: class Controller{ public Response getBestStudentForSchool( Request req ){ School school = repo.get( School.class, req.getParam( "schlId" ).asInt() ); Student bestStudent = school.getBe
class Controller{
public Response getBestStudentForSchool( Request req ){
School school = repo.get( School.class, req.getParam( "schlId" ).asInt() );
Student bestStudent = school.getBestStudent();
...
}
}
- Foo控制器调用“FooService”
- FooService调用FooRepository.getById()方法来获取一些Foo
- FooRepository进行一些Hibernate调用以加载Foo对象
- FooService与Foos进行一些交互。它可以使用相关的TransactionalFooService来处理需要在事务中一起完成的事情
- FooService要求FooRepository保存Foos
- 从Foo获取其他服务和对象很烦人。它不是SpringBean,它是由Hibernate加载的
- 让一个Foo做一些事务性的事情是很烦人的
- 很难决定Foo是否应该负责选择何时拯救自己。如果调用foo.setName(),foo是否应该保持更改?它是否应该等到调用foo.save()时再运行?foo.save()是否应该调用FooRepository.save(这个)
但我想避开这种设计,我想知道其他Spring的用途是什么?你有没有用一些花哨的技巧来对付它,比如在加载时编织(我不太习惯)?你还有别的把戏吗?您认为过程性很好吗?您可以让Spring使用AOP将您的服务注入到您的Hibernate实例化实例中。您还可以使用拦截器让Hibernate执行同样的操作 看 关于“让一个Foo以事务方式做一些事情很烦人”,我希望您的服务实现会知道/关心事务,如果您现在正在域模型中使用服务接口,那么现在应该不会那么烦人了 我怀疑,决定何时保存域模型取决于它是什么以及您正在使用它做什么
FWIW我倾向于产生相同类型的贫血结构,但我已经做到了,现在我知道可以用一种更合理的方法来实现它。听起来你的应用程序是围绕程序编码原则设计的。这将阻碍您尝试进行的任何面向对象编程 Foo可能没有它控制的行为。如果您的业务逻辑最小,那么不使用模式也是可以接受的。一个模式有时是有意义的 当这种逻辑开始增长时,问题就出现了。将事务脚本重构为域模型不是最容易的事情,但肯定不是最困难的。如果您有大量关于Foo的逻辑,我建议您转到域模型模式。封装的好处使得理解发生了什么以及谁参与了什么变得非常容易 如果您想让
Foo.Expire()。可能通过foosrepository
使用的工厂,在对象创建时连接foo.onexpatition+=FooService.ExpireFoo(foo.Id)
先好好想想。很有可能一切都已经准备就绪了。。。现在
祝你好运 我认为有一种简单的重构模式可以解决您的问题
将服务注入到存储库中
在返回Foo之前,请设置其“FooService”
现在让您的FooController从FooRepository中请求适当的Foo
现在在你的Foo上调用你想要的方法。如果它不能自己实现它们,让它调用FooService上的适当方法
现在,通过我喜欢在Foo上调用的“bucket bridge”方法删除对FooService的所有调用(它只是将参数传递给服务)
从现在起,无论何时您想要添加一个方法,都要将它添加到Foo
仅当出于性能原因确实需要时才向服务添加内容。与往常一样,应该通过模型对象调用这些方法
这将帮助您向更丰富的领域模型发展。它还保留了单一责任原则,因为所有依赖DB的代码都保留在FooService实现中,并帮助您将业务逻辑从FooService迁移到Foo。如果您想将后端切换到另一个DB或内存或模拟(用于测试),则无需更改任何内容,只需更改FooService层
^我假设FooService执行DB调用,这在ORM中执行起来太慢了,比如选择与给定Foo共享属性X的最新Foo。这就是我所见过的大多数工作方式
范例
而不是:
class Controller{
public Response getBestStudentForSchool( Request req ){
Student bestStudent = StudentService.findBestPupilForSchool( req.getParam( "schlId" ).asInt() );
...
}
}
你会朝着这样的方向发展:
class Controller{
public Response getBestStudentForSchool( Request req ){
School school = repo.get( School.class, req.getParam( "schlId" ).asInt() );
Student bestStudent = school.getBestStudent();
...
}
}
我希望你会同意这一点,它似乎已经变得更富有了。现在,您正在进行另一个数据库调用,但如果您将学校缓存在会话中,则惩罚是可以忽略的。我担心任何真正的OOP模型的效率都会低于您正在使用的贫血模型,但是通过代码清晰性减少bug应该是值得的。一如既往,YMMV.我向您推荐Doug Rosenberg和Matt Stephens的《使用UML进行用例驱动的对象建模》一书。它讨论了ICONIX过程——一种软件开发方法,也讨论了贫血领域模型。这也是Martin Fowler在其网站上开发的一个主题。但我们如何实现usi