Grails - 控制器和后端紧密耦合

时间:2012-10-19 20:24:49

标签: grails

当您使用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...
}

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

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

2 个答案:

答案 0 :(得分:0)

此模型非常适用于Java Web应用程序和所有。 Rails(和Grails跟随它)社区只是试图在这里打破范式,让它更简单。我的意思是,如果这个实体可以简单地完成这项工作,你为什么要委托一个服务类来操纵一个实体呢?如果实体做这项工作很自然,那就不要带别人去做。这样,您就可以避免使用Anemic Model,因为您的对象不仅仅是数据持有者,而且还知道如何运营自己的业务。

话虽如此,有时您最好使用服务类对您的实体进行操作。例如,如果它同时涉及不同类型的实体等等......那么,当它不是“自然的”(并且你必须强制使其工作)时,实体本身就要负责操作,然后一个服务类是要走的路。基于Rails的This article提供了有关服务类使用的一些提示。

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

答案 1 :(得分:0)

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

您是正确的,通常,您不希望将大多数GORM查询放在控制器中,因为控制器应该用于与前端进行交互。您当然可以将查询/业务逻辑放入Services或将查询直接放入Domain类。这就是Grails Services支持声明式事务处理的原因。