具有Groovy'with'闭包的重复try-catch块?

sme*_*eeb 5 groovy lambda closures

我有以下Groovy类:

@Slf4j
class WidgetService {
    WidgetDao widgetDao = new WidgetDao()

    createWidget(String name, int type) {
        try {
            widgetDao.createWidget(name, type)
        } catch(WidgetException wexc) {
            log.error(wexc)
            int x = doFizz()
            long y = doBuzz(x)
            determineHowToHandle(y)
        }
    }

    Widget getWidgetById(Long id) {
        try {
            widgetDao.getWidgetById(id)
        } catch(WidgetException wexc) {
            log.error(wexc)
            int x = doFizz()
            long y = doBuzz(x)
            determineHowToHandle(y)
        }
    }

    Widget getWidgetByName(String name) {
        try {
            widgetDao.getWidgetByName(name)
        } catch(WidgetException wexc) {
            log.error(wexc)
            int x = doFizz()
            long y = doBuzz(x)
            determineHowToHandle(y)
        }
    }

    def deleteWidget(Widget w) {
        try {
            widgetDao.deleteWidget(w)
        } catch(WidgetException wexc) {
            log.error(wexc)
            int x = doFizz()
            long y = doBuzz(x)
            determineHowToHandle(y)
        }
    }

    ...dozens of more methods with *exact* same catch block
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我的try-catch块中有很多重复的样板代码.如果我可以定义一个闭包或某种基于AOP的处理程序,只需将widgetDao感兴趣的方法作为lambda或类似的东西传递给闭包/处理程序,那就太好了:

def createWidgetClosure = { it =>
    widgetDao.createWidget(it.name, it.type)
}

def getWidgetByIdClosure = { it =>
    widgetDao.getWidgetById(it.id)
}

def tryCatchClosure = { closure =>
    try {
        closure()
    } catch(WidgetException wexc) {
        log.error(wexc)
        int x = doFizz()
        long y = doBuzz(x)
        determineHowToHandle(y)
    }
}
Run Code Online (Sandbox Code Playgroud)

这样我的`WidgetService就可以看起来像这样:

@Slf4j
class WidgetService {
    WidgetDao widgetDao = new WidgetDao()

    createWidget(String name, int type) {
        tryCatchClosure(createWidgetClosure())
    }

    Widget getWidgetById(Long id) {
        tryCatchClosure(getWidgetByIdClosure())
    }

    ...dozens of more methods with *exact* same catch block
}
Run Code Online (Sandbox Code Playgroud)

这可能吗?如果是这样,怎么样?

dma*_*tro 5

你可以使用tryCatchClosure你现在拥有的东西,如下所示.您甚至可以创建tryCatchClosure一个Closure以参数为参数的方法.

class WidgetService {
    WidgetDao widgetDao = new WidgetDao()

    def tryCatchClosure(Closure closure) {
        try {
            closure()
        } catch(WidgetException wexc) {
            log.error(wexc)
            int x = doFizz()
            long y = doBuzz(x)
            determineHowToHandle(y)
        }
    }

    createWidget(String name, int type) {
        tryCatchClosure {
            widgetDao.createWidget(name, type)
        } 
    }

    Widget getWidgetById(Long id) {
        tryCatchClosure {
            widgetDao.getWidgetById(id)
        }
    }

    Widget getWidgetByName(String name) {
        tryCatchClosure {
            widgetDao.getWidgetByName(name)
        }
    }

    def deleteWidget(Widget w) {
        tryCatchClosure {
            widgetDao.deleteWidget(w)
        }
    }

    // ...dozens of more methods with *exact* same catch block
}
Run Code Online (Sandbox Code Playgroud)

或者您也可以WidgetDao通过覆盖invokeMethod其metaClass 上的方法来拦截每个方法调用并处理异常(try/catch).与此类似.

  • 与`@ Delegate`一起归结为oneliner和一些错误处理代码.得爱groovy (2认同)