[Java] 设计模式:代码形状 - lambda表达式的一个应用
程序员文章站
2022-03-28 18:15:15
[Java] 设计模式:代码形状 lambda表达式的一个应用 Code Shape 模式 这里介绍一个模式:Code Shape。没听过,不要紧,我刚刚才起的名字。 作用 在应用程序的开发中,我们一般会使用多层架构。 在这种情况下,每一层的方法往往会呈现相同的代码结构。这里称之为 层的代码形状 。 ......
[Java] 设计模式:代码形状 - lambda表达式的一个应用
Code Shape 模式
这里介绍一个模式:Code Shape。没听过,不要紧,我刚刚才起的名字。
作用
在应用程序的开发中,我们一般会使用多层架构。
在这种情况下,每一层的方法往往会呈现相同的代码结构。这里称之为层的代码形状。
比如:在数据访问层,每个写数据方法都会有以下的代码:
- 获取数据库连接
- 建立事务
- 写入数据
- 提交事务
- 如果发生异常,回滚数据。
除此以外,我们有时也会希望增加一些架构功能,比如: - 统一处理权限认证
- 统一处理异常
- 记录日志
- 对性能做profiling
- 记录方法的参数
那么,Code Shape模式通过使用Java lambda表达式,达到这样的作用:
提供了一种灵活的方式,管理一个层中,每个方法的形状。
代码示例
这里提供了一个代码示例,完成了以下功能:
- 在调用一个层方法前,记录日志
- 记录方法参数
- 在调用一个层方法后,记录日志
- 如果有,记录方法的返回值
- 当调用一个层方法,发生异常时,记录日志
预备知识
关于Java 8的Lambda Expressions。请参考。
Java提供java.util.function.Consumer
和java.util.function.Function
。方便我们使用Lambda表达式。
Consumer是给没有返回值的方法用的。Function是给有返回值的方法用的。
遗憾的是它们只支持一个输入参数。
因此,如果需要可以写支持多个参数的接口。比如,在我们的例子中用到了:
- ConsumerTwo
@FunctionalInterface public interface ConsumerTwo<One, Two> { public void accept(One one, Two two); }
- FunctionTwo
@FunctionalInterface public interface FunctionTwo<One, Two, R> { public R apply(One one, Two two); }
Annotation FunctionalInterface说明这是一个方法接口(function interface),接口中只定义了一个方法。
入口代码
入口代码调用了三个示例,说明了各种情况。
第一种情况:调用一个没有返回值的方法。
第二种情况:调用一个没有返回值的方法,实际运行中会发生异常。
第三种情况:调用一个有返回值的方法。
代码如下:
- Main.java
public class Main { public static void main(String[] args) { pattern.CodeShapeSample br = new pattern.CodeShapeSample(); // call business rule one br.businessRuleOne("Jack", "is man"); // call business rule two, will get an exception try { br.businessRuleTwoThrowException("Tom", "is woman"); } catch (Exception e) {} // call business rule three which has a return. String value = br.businessRuleThree("Mary", "is woman"); } }
Code Shape 设计模式代码
- CodeShapeSample
package pattern; import java.text.MessageFormat; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; public class CodeShapeSample { /* * This is a consumer sample */ public void businessRuleOne(final String name, final String value) { CodeShapePattern.consumerShape.accept((o) -> { System.out.println(name + " " + value); }, Arrays.asList(name, value)); } /* * This is a consumer with exception sample */ public void businessRuleTwoThrowException(final String name, final String value) { CodeShapePattern.consumerShape.accept((o) -> { throw new RuntimeException("failure!"); }, Arrays.asList(name, value)); } /* * This is a function sample */ public String businessRuleThree(final String name, final String value) { return CodeShapePattern.<String>getFunctionShape().apply((o) -> { return name + " " + value; }, Arrays.asList(name, value)); } }
- CodeShapePattern
package pattern; import java.text.MessageFormat; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; public class CodeShapePattern { public static ConsumerTwo<Consumer<Object>, List<Object>> consumerShape = (body, params) -> { StackTraceElement caller = new Exception().getStackTrace()[2]; String method = caller.getClassName() + "#" + caller.getMethodName(); try { System.out.println(""); System.out.println("========"); System.out.println(MessageFormat.format("start method ''{0}''", method)); if (params != null) { for(Object param : params) { System.out.println(MessageFormat.format("parameter : ''{0}''", param.toString())); } } System.out.println("---- start body ----"); body.accept(null); System.out.println("---- end body ----"); System.out.println(MessageFormat.format("end method ''{0}''", method)); } catch (Exception e) { System.out.println(MessageFormat.format("error method ''{0}'': {1}", method, e.getMessage())); throw e; } }; public static <R> FunctionTwo<Function<Object, R>, List<Object>, R> getFunctionShape() { FunctionTwo<Function<Object, R>, List<Object>, R> function = (body, params) -> { R ret = null; StackTraceElement caller = new Exception().getStackTrace()[2]; String method = caller.getClassName() + "#" + caller.getMethodName(); try { System.out.println(""); System.out.println("========"); System.out.println(MessageFormat.format("start method ''{0}''", method)); if (params != null) { for(Object param : params) { System.out.println(MessageFormat.format("parameter : ''{0}''", param.toString())); } } System.out.println("---- start body ----"); ret = body.apply(null); System.out.println("---- end body ----"); System.out.println(MessageFormat.format("end method ''{0}'', return ''{1}''", method, ret.toString())); } catch (Exception e) { System.out.println(MessageFormat.format("error method ''{0}'': {1}", method, e.getMessage())); throw e; } return ret; }; return function; } }
代码说明1:使用Consumer
现在,所有的代码已经呈上了。我们逐一解释。
- 业务层代码
由于这个业务层方法是一个没有返回值的方法,所以使用了CodeShapePattern.consumerShape
。
传入参数有两个。
第一个是:业务层逻辑。
第二个是:方法的参数,用于统一管理。
/* * This is a consumer sample */ public void businessRuleOne(final String name, final String value) { CodeShapePattern.consumerShape.accept((o) -> { // business rule code System.out.println(name + " " + value); }, Arrays.asList(name, value)); }
- Code Shape 模式代码 - Consumer
实际上consumerShape是一个静态变量,实现了统一管理的功能。
可以看出这个Consumer里面套用了一个Consumer。
里面的Consumer就是业务逻辑。,在业务层方法中,想怎么写,就怎么写。
顺便说一句,这个Consumer的输入参数是没有意义的。我们可以定义一个ConsumerZero来简化这部分。
public static ConsumerTwo<Consumer<Object>, List<Object>> consumerShape = (body, params) -> { StackTraceElement caller = new Exception().getStackTrace()[2]; String method = caller.getClassName() + "#" + caller.getMethodName(); try { System.out.println(""); System.out.println("========"); System.out.println(MessageFormat.format("start method ''{0}''", method)); if (params != null) { for(Object param : params) { System.out.println(MessageFormat.format("parameter : ''{0}''", param.toString())); } } System.out.println("---- start body ----"); body.accept(null); System.out.println("---- end body ----"); System.out.println(MessageFormat.format("end method ''{0}''", method)); } catch (Exception e) { System.out.println(MessageFormat.format("error method ''{0}'': {1}", method, e.getMessage())); throw e; } };
简化版:
public static ConsumerTwo<Consumer<Object>, List<Object>> consumerShape = (body, params) -> { try { body.accept(null); } catch (Exception e) { throw e; } };
代码说明2:使用Function
- 业务层代码
由于这个业务层方法是一个有返回值的方法,所以使用了CodeShapePattern.<R>getFunctionShape()
。
getFunctionShape()是一个泛型方法,泛型类是返回值的类型。
输入参数有两个。
第一个是:业务层逻辑,有返回。
第二个是:方法的参数,用于统一管理。
/* * This is a function sample */ public String businessRuleThree(final String name, final String value) { return CodeShapePattern.<String>getFunctionShape().apply((o) -> { // business rule code return name + " " + value; }, Arrays.asList(name, value)); }
- Code Shape 模式代码 - Function
实际上getFunctionShape是一个静态泛型方法,实现了统一管理的功能。
可以看出这个方法的返回Function里面套用了一个Function。
里面的Function就是业务逻辑。,在业务层方法中,想怎么写,就怎么写。
顺便说一句,里面这个Function的输入参数是没有意义的。我们可以定义一个FunctionZero来简化这部分。
public static <R> FunctionTwo<Function<Object, R>, List<Object>, R> getFunctionShape() { FunctionTwo<Function<Object, R>, List<Object>, R> function = (body, params) -> { R ret = null; StackTraceElement caller = new Exception().getStackTrace()[2]; String method = caller.getClassName() + "#" + caller.getMethodName(); try { System.out.println(""); System.out.println("========"); System.out.println(MessageFormat.format("start method ''{0}''", method)); if (params != null) { for(Object param : params) { System.out.println(MessageFormat.format("parameter : ''{0}''", param.toString())); } } System.out.println("---- start body ----"); ret = body.apply(null); System.out.println("---- end body ----"); System.out.println(MessageFormat.format("end method ''{0}'', return ''{1}''", method, ret.toString())); } catch (Exception e) { System.out.println(MessageFormat.format("error method ''{0}'': {1}", method, e.getMessage())); throw e; } return ret; }; return function; }
简化版:
public static <R> FunctionTwo<Function<Object, R>, List<Object>, R> getFunctionShape() { FunctionTwo<Function<Object, R>, List<Object>, R> function = (body, params) -> { R ret = null; try { ret = body.apply(null); } catch (Exception e) { throw e; } return ret; }; return function; }
输入结果
======== start method 'pattern.CodeShapeSample#businessRuleOne' parameter : 'Jack' parameter : 'is man' ---- start body ---- Jack is man ---- end body ---- end method 'pattern.CodeShapeSample#businessRuleOne' ======== start method 'pattern.CodeShapeSample#businessRuleTwoThrowException' parameter : 'Tom' parameter : 'is woman' ---- start body ---- error method 'pattern.CodeShapeSample#businessRuleTwoThrowException': failure! ======== start method 'pattern.CodeShapeSample#businessRuleThree' parameter : 'Mary' parameter : 'is woman' ---- start body ---- ---- end body ---- end method 'pattern.CodeShapeSample#businessRuleThree', return 'Mary is woman'