如何重构作为Groovy中方法调用的参数的闭包的重复?

时间:2014-07-16 23:42:37

标签: grails groovy closures

考虑一下这个真实世界的例子,这个例子是为了使“GET'和' POST'通过Rest Client Builder(Grails插件)调用相同的REST服务端点。我不喜欢重复,因为标头和内容类型设置是相同的,但我不知道如何重构常见的部分,因为它们正在调用传递给get()或post()方法调用的闭包上的方法。请提供一个具体的例子,说明你的答案中重复的重构。

   private def doGetCall(String endpoint, def config) {
       def response = new RestBuilder().get(config.baseURI+endpoint) {
           contentType("application/json")
           header("Authorization", "ApiKey " + config.base64EncodedApiKey)
           header("ClientId", config.clientId)
       }

       handleResponse(response, config, endpoint);
       return response;
   }

   private def doPostCall(String endpoint, def payload, def config) {
       def response = new RestBuilder().post(config.baseURI+endpoint) {
           contentType("application/json")
           header("Authorization", "ApiKey " + config.base64EncodedApiKey)
           header("ClientId", config.clientId)
           json(payload)
       }

       handleResponse(response, config, endpoint, payload)
       return response;
   }

2 个答案:

答案 0 :(得分:2)

这样就够了吗?

class RestTestService {
    def rest

    def methodMissing(String name, args) {
        if( !( name in ['get', 'post'] ) ) { // can add PUT & DELETE in future
            // throw missing method exception for method names other than above
            throw new MissingMethodException(
               "Http Method $name does not exist or not yet implemented.") 
        }

        def (endpoint, config, payload) = args?.toList()

        def response = rest."$name"(config.baseURI + endpoint) {
            contentType( "application/json" )
            header("Authorization", "ApiKey " + config.base64EncodedApiKey )
            header( "ClientId", config.clientId )
            if ( name == 'post' && payload ) {
                json( payload )
            }
        }

        handleResponse(response, config, endpoint)

        return response
    }

    private void handleResponse(def response, def config, def endpoint) { ... }

    public def doGetCall(String endpoint, def config) {
        get( endpoint, config )
    }

    public def doPostCall(String endpoint, def payload, def config) {
        post( endpoint, config, payload )
    }
}

//resources.groovy
beans = {
    rest(grails.plugins.rest.client.RestBuilder)
}

上面使用methodMissing来决定在运行时调用哪个http方法 另请注意,我建议不要为每个http调用创建RestBuilder,而是将其用作resources.groovy中所示的bean,并在使用它时将其注入类中。如果它是一个grails工件(控制器,服务),那么它将自动装配,否则必须适当地连接bean rest。 您可以使用doGetCalldoPostCall进行抽象,也可以根据需要将其删除。

答案 1 :(得分:2)

Groovy 1.8添加了Closure组合,因此如果您使用的是使用Groovy 1.8或更高版本的Grails版本:

private def doGetCall(String endpoint, def config) {
    def response = new RestBuilder().get(config.baseURI+endpoint, composeRequest(config))

    handleResponse(response, config, endpoint);
    return response;
}

private def doPostCall(String endpoint, def payload, def config) {
    def response = new RestBuilder().post(config.baseURI+endpoint, composeRequest(config, { json(payload) }))

    handleResponse(response, config, endpoint, payload)
    return response;
}

private def composeRequest(def config, Closure clos = null) {
    def request = {
        contentType("application/json")
        header("Authorization", "ApiKey " + config.base64EncodedApiKey)
        header("ClientId", config.clientId)
    }
    if (clos != null) {
        request = request << clos
    }
    request
}