Grails - 服务层的使用 [英] Grails - the use of service layer

查看:92
本文介绍了Grails - 服务层的使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我想更新非简单的域对象时,我在组织代码时遇到了问题。问题是要分开控制器和服务层的职责。更明确地说,假设我们有一个域类Client,它依赖于Address等等其他域类



在视图中有一个gsp用于编辑某些客户端属性,其中包括一些嵌套属性,如街道地址。



当我想更新这些字段时,我在控制器上调用update方法(本例中为ClientController)。



我喜欢功能来自验证时的域类的错误。就像我在Controller中写的一样

 客户端客户端= Client.get(params.id)
client.properties = params
client.validate()

如果客户端现在有错误,很容易显示他们在编辑视图中。

但是,我认为更新,保存和从数据库获取客户端(Client.get(theId))应该由服务层。在我的情况下,我必须在更新客户端之前更新或创建其他域对象(如地址)。



所以我的一个问题是API应该如何对于服务层?

  public ... updateClient(...)

在文献中,他们有更新人的年龄的微不足道的例子。所以,他们的API由人的身份和新时代组成。但是,就我而言,我从视图中获得了大约10个参数,它们只是客户所有属性的一个子集,我不知道这些参数中哪一个已经发生了变化。


  1. 我希望在控制器中拥有一个客户端,如果它有验证错误,我可以验证并重新发送到编辑视图。

  2. 喜欢处理来自服务层的数据库交互和事务。

我怎样才能组合这些?不同层面应该对更新负责什么?服务层的API应该如何看待更新?



如果有一个很好的参考实现,我会很乐意研究它。很多时候,服务层不幸全部或部分被忽略。 解决方案

这个谜题的缺失部分是命令对象。这些类表示您的API在您的服务中的合同,并为您提供具体的类视图和验证的能力。让我们来看一个例子。



给定一个 Client 的域类作为地址和几个电话实例您的服务层可能如下所示:

  ... 
class ClientService {
def updateClient(ClientUpdateCommand cmd){

}
}
...

虽然ClientUpdateCommand看起来像这样:

  @ grails.validation.Validateable $ b $ class ClientUpdateCommand {
Long id
字符串名称
List< PhoneUpdateCommand> phoneNumbers = []
AddressUpdateCommand address = new AddressUpdateCommand()
...
静态约束{
id(可空值:false)
名称(空值:false,空白:false,size:1..50)
...
}
...
}

您会注意到,该命令对象由其他命令对象组成,并且具有验证约束。看起来你在这里复制你的域类,但是我发现你的应用程序越复杂,那么域类和你的命令对象之间就会出现更多的差异。



接下来是在控制器和视图中使用命令对象。一个控制器方法可能看起来像这样:

 类ClientController {
...
def clientService
...
def edit(ClientUpdateCommand cmd){
...
cmd = clientService.load(cmd.id)
Map model = [client:cmd]
render(view:'edit',model:model)
}
def update(ClientUpdateCommand cmd){
Map model = [client:cmd]
if cmd.hasErrors(){
render(view:'edit',model:model]
return
} else {
clientService.update(cmd)
.. 。
}
...
}
}



<我已经从控制器中留下了很多东西,因为我不想让你知道细节,而是显示一个命令对象如何替换域实例。在某些方面,它有点更多的工作,但它会让你完全离开从操纵域类并委托给你创建的服务,你也不会让命令对象替换您的视图的模型的域类实例。我不会给你任何GSPs的例子,因为当使用像这样的命令对象时,它们确实不会有太大的变化。



我确信可以有整个关于这个主题的书籍章节,但希望这给你一些洞察力,你可以看到你的问题的答案是:命令对象。


I have problems in organizing my code when I want to update a non-simple domain object. The problem is to separate responsibilities for the controller and the service layer.

More explicitly, assume that we have a domain class Client that depends on other domain classes like Address and so on.

In the view there is a gsp for editing some of the Clients properties including some of the nested properties like street on the Address.

When I would like to update those fields I call the update method on a Controller (in this case the ClientController).

I like the feature coming from the errors of a domain class when validated. Like if I in the Controller write

Client client = Client.get(params.id)
client.properties = params
client.validate()

If the client now has errors it is very easy to display them in the edit view.

But, I thought that updating, saving and getting the client from the database (Client.get(theId)) should be handled by the service layer. In my case I have to update or create other domain objects (like the Address) before I update the Client.

So one of my questions are how should the API look like for the service layer?

public ... updateClient(…)

In the literature they have the trivial example of updating the age of a person. So, their API consists of the id of the person and the new age. But, in my case I have about ten params from the view and they are just a subset of all properties of a client and I don't know which one of these that have changed.

  1. I would like to have a Client in the controller that I can validate and resend to the edit view if it has validation errors.
  2. I would like to handle the database interactions and transactions from the service layer.

How can I combine these? What responsibilities should the different layers have regarding update? How should the API of the service layer look like regarding update?

If there is a good reference implementation somewhere I would be happy to study it. Many times the service layer is unfortunately totally or partially ignored.

解决方案

The missing piece of this puzzle is command objects. These classes represent the contract for your API into your services and provide you the ability to have a concrete class for your views and for validation. Let's look at an example.

Given a domain class of Client which as an Address and several Phone instances your Service layer might look like this:

...
class ClientService {
  def updateClient(ClientUpdateCommand cmd) {
    ..
  }
}
...

While the ClientUpdateCommand looks something like this:

@grails.validation.Validateable
class ClientUpdateCommand {
  Long id
  String name
  List<PhoneUpdateCommand> phoneNumbers = []
  AddressUpdateCommand address = new AddressUpdateCommand()
  ...
  static constraints {
    id(nullable: false)
    name(nullable: false, blank: false, size:1..50)
    ...
  }
  ...
}

You will note that this command object is composed of other command objects, and has constraints for validation. It may seem like you are replicating your domain classes here, but I have found that the more complex your application then more differences will appear between the domain classes and your command objects.

Next up is the use of the command object within your controller and your views. A controller method may look something like this:

Class ClientController {
  ...
  def clientService
  ...
  def edit(ClientUpdateCommand cmd) {
    ...
    cmd = clientService.load(cmd.id)
    Map model = [client: cmd]
    render(view: 'edit', model: model)
  }
  def update(ClientUpdateCommand cmd) {
    Map model = [client: cmd]
    if (cmd.hasErrors() {
      render(view: 'edit', model: model]
      return
    } else {
      clientService.update(cmd)
      ...
    }
    ...
  }
}

I have left a lot out of the controller as I didn't want to bore you with the details but rather show how a command object replaces the domain instance. In some ways it's a little bit more work but it moves you completely away from manipulating the domain classes and delegates that to the service you have created. You will also notice that the command object replaces the domain class instance for your model for your views. I won't bother giving you any examples of the GSPs since they really don't change much when using command objects like this.

I'm sure there could be entire chapters of books written on the subject, but hopefully this gives you some insight and you can see that the answer to your question(s) is: Command objects.

这篇关于Grails - 服务层的使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆