0

当您在 grails 中生成控制器时,控制器直接调用域层上的方法 - 我很不明白这一点,我的每一点都在告诉我这是一种错误,因为您将后端与前端紧密耦合。我认为这属于服务层。

由于在服务层中为域对象上定义的所有方法创建一组等效的方法会非常难看,因此我创建了它AbstractService以将所有(缺失的)方法调用从服务层委托给域层:

abstract class AbstractService {
    def entityType

    /**
     * By default, this method takes the name of the service that extends this
     * class, removes the suffix 'Service' and tries to create the Class object
     * from the resulting name. Override at will.
     */
    protected Class getEntityType() {
        if (!entityType) {
            try {
                entityType = Class.forName(this.class.name[0..-8], false, Thread.currentThread().contextClassLoader)
            } catch (ClassNotFoundException e) {
                throw new ClassNotFoundException("Class ${this.class.name[0..-8]} could not be found. Please "
                                + "override AbstractService#getEntityType() for ${this.class}.")
            }
        }
        entityType
    }

    def methodMissing(String name, args) {
        try {
            if (getEntityType()?.metaClass?.getStaticMetaMethod(name)) {
                getEntityType().invokeMethod(name, args)
            } else if (args?.last()?.metaClass?.getMetaMethod(name)) {
                args.last().invokeMethod(name, args.take(args.size() - 1))
            } else {
                throw new MissingMethodException(name, this.class, args)
            }
        } catch (MissingMethodException e) {
            throw new MissingMethodException(name, this.class, args)
        }
    }
}

然后我只是扩展此服务,例如:

class UserService extends AbstractService {
}

然后我的控制器可以看起来像这样:

class UserController {
    def userService

    def create() {
        userService.save(new User(params))
    }

    def list() {
        userService.list(params)
    }

    // et cetera...
}

你不觉得这样更好吗?多亏了依赖注入,我可以重写整个业务层,而无需更改控制器中的代码——这就是我们使用依赖注入的原因,不是吗?

感谢您的回答,我想听到尽可能多的意见。

4

2 回答 2

0

该模型在 Java Web 应用程序和所有应用程序中非常常用。Rails(以及遵循它的 Grails)社区只是试图打破这里的范式,让它变得更简单。我的意思是,如果这个实体可以简单地完成这项工作,你为什么要委托一个服务类来操纵一个实体?如果实体做这项工作是自然的,那么不要让其他人来做。这样,您就可以避免贫血模型,因为您的对象不仅是数据持有者,而且他们还知道如何运营自己的业务。

话虽如此,有时您最好使用服务类对您的实体进行操作。例如,如果它同时涉及不同类型的实体等等......所以,当它不是“自然的”(并且你必须强制使其工作)时,实体本身来处理操作,那么服务类就是要走的路。这篇基于 Rails 的文章给出了一些关于使用服务类的技巧。

而且您并没有将控制器与模型紧密耦合(您说的是后端和前端,但我想这就是您的意思)。控制器最终将需要使用模型,无论是实体本身还是操作它的服务类(也是模型)。

于 2012-10-19T21:01:10.230 回答
0

脚手架控制器代码并不能真正代表理想的应用程序架构。请记住,生成的脚手架代码只是生成应用程序的 CRUD 部分的起点。

您是对的,一般来说,您不想将大部分 GORM 查询放在控制器中,因为控制器应该用于与前端交互。您当然可以将查询/业务逻辑放入服务中,也可以将查询直接放入域类中。这就是 Grails 服务支持声明式事务处理的原因。

于 2012-10-21T18:08:37.813 回答