[Java] 设计模式: Code Shape - 管理你的代码结构

Code Shape 设计模式

这里介绍一个设计模式: Code Shape。

如果你没有听说的,没问题。这个名字是我刚刚起的。

作用

在应用软件开发中,我们经常会采用多层架构。在每一层中,不同的方法往往呈现相同的代码结构。

这里我们称之为:Code Shape

比如:在数据访问层,写方法都可能有下面这些代码:

  • 获取数据库连接
  • 创建一个事务
  • 写入数据
  • 提交事务
  • 如果发生异常,回滚事务

除此之外,有时,架构师希望增加一些架构功能,比如:

  • 统一处理权限认证
  • 统一处理异常
  • 记录日志
  • 对性能做profiling
  • 记录方法的参数值

这时,设计模式 Code Shape 通过使用Lambda表达式,实现了上面的需求。

提供了一种灵活的方式,管理每层方法的代码结构。

代码示例

本位提供了一个代码示例,完成下面功能:

  • 在调用一个业务逻辑之前,写一个日志。
  • 在调用一个业务逻辑之后,写一个日志。
  • 在调用一个业务逻辑时发生异常,写一个日志。
  • 记录方法的参数值。
  • 如果有,记录返回值。

预备知识

关于 Java 8 Lambda 表达式,请参考 这里

Java 提供了 java.util.function.Consumerjava.util.function.Function,方便我们去使用Lambda表达式。

Consumer 被用于没有返回值的方法,Function 被用于有返回值的方法。

不幸的是,这两个接口只支持一个输入参数。

如果需要,我们需要写一些接口,来支持多个输入参数。

这是,提供了支持两个输入参数的例子:

  • ConsumerTwo
  1. @FunctionalInterface
  2. public interface ConsumerTwo<T, T2> {
  3. public void accept(T t, T2 t2);
  4. }
  • FunctionTwo
  1. @FunctionalInterface
  2. public interface FunctionTwo<T, T2, R> {
  3. public R apply(T t, T2 t2);
  4. }

Annotation FunctionalInterface 标示这个接口是一个function interface,内部只定义了一个方法。

代码:Main类

这个Main类调用了三个例子:

第一个例子:调用了一个没有返回值的业务逻辑方法。

第二个例子:调用了一个没有返回值的业务逻辑方法,实际上,会抛出异常。

第三个例子:调用了一个有返回值的业务逻辑方法。

代码:

  • Main.java
  1. public class Main {
  2. public static void main(String[] args) {
  3. pattern.CodeShapeSample br = new pattern.CodeShapeSample();
  4. // call business rule one
  5. br.businessRuleOne("Jack", "is man");
  6. // call business rule two, will get an exception
  7. try {
  8. br.businessRuleTwoThrowException("Tom", "is woman");
  9. }
  10. catch (Exception e) {}
  11. // call business rule three which has a return.
  12. String value = br.businessRuleThree("Mary", "is woman");
  13. }
  14. }

代码:Code Shape 设计模式

  • CodeShapeSample
  1. package pattern;
  2. import java.text.MessageFormat;
  3. import java.util.Arrays;
  4. import java.util.List;
  5. import java.util.function.Consumer;
  6. import java.util.function.Function;
  7. public class CodeShapeSample {
  8. /*
  9. * This is a consumer sample
  10. */
  11. public void businessRuleOne(final String name, final String value) {
  12. CodeShapePattern.consumerShape.accept((o) -> {
  13. // here is business rule logical
  14. System.out.println("here is business rule logical 1.");
  15. }, Arrays.asList(name, value));
  16. }
  17. /*
  18. * This is a consumer with exception sample
  19. */
  20. public void businessRuleTwoThrowException(final String name, final String value) {
  21. CodeShapePattern.consumerShape.accept((o) -> {
  22. // here is business rule logical
  23. System.out.println("here is business rule logical 2.");
  24. throw new RuntimeException("failure!");
  25. }, Arrays.asList(name, value));
  26. }
  27. /*
  28. * This is a function sample
  29. */
  30. public String businessRuleThree(final String name, final String value) {
  31. return CodeShapePattern.<String>getFunctionShape().apply((o) -> {
  32. // here is business rule logical
  33. System.out.println("here is business rule logical 3.");
  34. return name + " " + value;
  35. }, Arrays.asList(name, value));
  36. }
  37. }
  • CodeShapePattern
  1. package pattern;
  2. import java.text.MessageFormat;
  3. import java.util.List;
  4. import java.util.function.Consumer;
  5. import java.util.function.Function;
  6. public class CodeShapePattern {
  7. public static ConsumerTwo<Consumer<Object>, List<Object>> consumerShape = (body, params) ->
  8. {
  9. StackTraceElement caller = new Exception().getStackTrace()[2];
  10. String method = caller.getClassName() + "#" + caller.getMethodName();
  11. try {
  12. System.out.println("");
  13. System.out.println("========");
  14. System.out.println(MessageFormat.format("start method ''{0}''", method));
  15. if (params != null) {
  16. for(Object param : params) {
  17. System.out.println(MessageFormat.format("parameter : ''{0}''", param.toString()));
  18. }
  19. }
  20. System.out.println("---- start body ----");
  21. body.accept(null);
  22. System.out.println("---- end body ----");
  23. }
  24. catch (Exception e) {
  25. System.out.println(MessageFormat.format("error method ''{0}'': {1}", method, e.getMessage()));
  26. throw e;
  27. }
  28. finally {
  29. System.out.println(MessageFormat.format("end method ''{0}''", method));
  30. }
  31. };
  32. public static <R> FunctionTwo<Function<Object, R>, List<Object>, R> getFunctionShape() {
  33. FunctionTwo<Function<Object, R>, List<Object>, R> function = (body, params) ->
  34. {
  35. R ret = null;
  36. StackTraceElement caller = new Exception().getStackTrace()[2];
  37. String method = caller.getClassName() + "#" + caller.getMethodName();
  38. try {
  39. System.out.println("");
  40. System.out.println("========");
  41. System.out.println(MessageFormat.format("start method ''{0}''", method));
  42. if (params != null) {
  43. for(Object param : params) {
  44. System.out.println(MessageFormat.format("parameter : ''{0}''", param.toString()));
  45. }
  46. }
  47. System.out.println("---- start body ----");
  48. ret = body.apply(null);
  49. System.out.println("---- end body ----");
  50. }
  51. catch (Exception e) {
  52. System.out.println(MessageFormat.format("error method ''{0}'': {1}", method, e.getMessage()));
  53. throw e;
  54. }
  55. finally {
  56. System.out.println(MessageFormat.format("end method ''{0}'', return ''{1}''", method, ret.toString()));
  57. }
  58. return ret;
  59. };
  60. return function;
  61. }
  62. }

代码说明 1:使用 Consumer

好了,这里已经提供了所有的代码。现在,让我们逐一解释。

  • 代码:业务逻辑

    由于下面这个业务规则方法没有返回值,所以使用CodeShapePattern.consumerShape

    这里有两个输入参数:

    第一个是:业务规则逻辑。

    第二个是:方法的参数值,用于内部使用。
  1. /*
  2. * This is a consumer sample
  3. */
  4. public void businessRuleOne(final String name, final String value) {
  5. CodeShapePattern.consumerShape.accept((o) -> {
  6. // here is business rule logical
  7. System.out.println("here is business rule logical 1.");
  8. }, Arrays.asList(name, value));
  9. }
  • 代码:Code Shape 设计模式 - Consumer

    我们可以看到,consumerShape 是一个静态变量,实现了统一的功能。

    这个 consumerShape 使用了一个嵌套的 Consumer

    内部的 Consumer 是业务规则逻辑, 在业务规则逻辑,你想怎么写,就怎么写。

    顺便说一句:内部的 Consumer的输入参数是没用的,我们可以定义一个 ConsumerZero 接口来简化代码。
  1. public static ConsumerTwo<Consumer<Object>, List<Object>> consumerShape = (body, params) ->
  2. {
  3. StackTraceElement caller = new Exception().getStackTrace()[2];
  4. String method = caller.getClassName() + "#" + caller.getMethodName();
  5. try {
  6. System.out.println("");
  7. System.out.println("========");
  8. System.out.println(MessageFormat.format("start method ''{0}''", method));
  9. if (params != null) {
  10. for(Object param : params) {
  11. System.out.println(MessageFormat.format("parameter : ''{0}''", param.toString()));
  12. }
  13. }
  14. System.out.println("---- start body ----");
  15. body.accept(null);
  16. System.out.println("---- end body ----");
  17. }
  18. catch (Exception e) {
  19. System.out.println(MessageFormat.format("error method ''{0}'': {1}", method, e.getMessage()));
  20. throw e;
  21. }
  22. finally {
  23. System.out.println(MessageFormat.format("end method ''{0}''", method));
  24. }
  25. };

简化版:

  1. public static ConsumerTwo<Consumer<Object>, List<Object>> consumerShape = (body, params) ->
  2. {
  3. try {
  4. body.accept(null);
  5. }
  6. catch (Exception e) {
  7. throw e;
  8. }
  9. finally {
  10. }
  11. };

代码说明 2:使用 Function

好了,这里已经提供了所有的代码。现在,让我们逐一解释。

  • 代码:业务逻辑

    由于下面这个业务规则方法有返回值,所以使用CodeShapePattern.<R>getFunctionShape()

    getFunctionShape()是一个泛型方法,这个泛型是业务逻辑方法的返回类型。

    这里有两个输入参数:

    第一个是:业务规则逻辑,有返回值。

    第二个是:方法的参数值,用于内部使用。
  1. /*
  2. * This is a function sample
  3. */
  4. public String businessRuleThree(final String name, final String value) {
  5. return CodeShapePattern.<String>getFunctionShape().apply((o) -> {
  6. // here is business rule logical
  7. System.out.println("here is business rule logical 3.");
  8. return name + " " + value;
  9. }, Arrays.asList(name, value));
  10. }
  • 代码:Code Shape 设计模式 - Function

    不同于consumerShape, getFunctionShape 是一个静态泛型方法,实现了统一的功能。

    这个 getFunctionShape 使用了一个嵌套的 Function

    内部的 Function 是业务规则逻辑, 在业务规则逻辑,你想怎么写,就怎么写。

    顺便说一句:内部的 Function的输入参数是没用的,我们可以定义一个 FunctionZero 接口来简化代码。
  1. public static <R> FunctionTwo<Function<Object, R>, List<Object>, R> getFunctionShape() {
  2. FunctionTwo<Function<Object, R>, List<Object>, R> function = (body, params) ->
  3. {
  4. R ret = null;
  5. StackTraceElement caller = new Exception().getStackTrace()[2];
  6. String method = caller.getClassName() + "#" + caller.getMethodName();
  7. try {
  8. System.out.println("");
  9. System.out.println("========");
  10. System.out.println(MessageFormat.format("start method ''{0}''", method));
  11. if (params != null) {
  12. for(Object param : params) {
  13. System.out.println(MessageFormat.format("parameter : ''{0}''", param.toString()));
  14. }
  15. }
  16. System.out.println("---- start body ----");
  17. ret = body.apply(null);
  18. System.out.println("---- end body ----");
  19. }
  20. catch (Exception e) {
  21. System.out.println(MessageFormat.format("error method ''{0}'': {1}", method, e.getMessage()));
  22. throw e;
  23. }
  24. finally {
  25. System.out.println(MessageFormat.format("end method ''{0}'', return ''{1}''", method, ret.toString()));
  26. }
  27. return ret;
  28. };
  29. return function;
  30. }

简化版:

  1. public static <R> FunctionTwo<Function<Object, R>, List<Object>, R> getFunctionShape() {
  2. FunctionTwo<Function<Object, R>, List<Object>, R> function = (body, params) ->
  3. {
  4. R ret = null;
  5. try {
  6. ret = body.apply(null);
  7. }
  8. catch (Exception e) {
  9. throw e;
  10. }
  11. finally {
  12. }
  13. return ret;
  14. };
  15. return function;
  16. }

输出结果

========

start method 'pattern.CodeShapeSample#businessRuleOne'

parameter : 'Jack'

parameter : 'is man'

---- start body ----

here is business rule logical 1.

---- end body ----

end method 'pattern.CodeShapeSample#businessRuleOne'

========

start method 'pattern.CodeShapeSample#businessRuleTwoThrowException'

parameter : 'Tom'

parameter : 'is woman'

---- start body ----

here is business rule logical 2.

error method 'pattern.CodeShapeSample#businessRuleTwoThrowException': failure!

end method 'pattern.CodeShapeSample#businessRuleTwoThrowException'

========

start method 'pattern.CodeShapeSample#businessRuleThree'

parameter : 'Mary'

parameter : 'is woman'

---- start body ----

here is business rule logical 3.

---- end body ----

end method 'pattern.CodeShapeSample#businessRuleThree', return 'Mary is woman'

[Java] 设计模式:代码形状 - lambda表达式的一个应用的更多相关文章

  1. Java基础教程(23)--lambda表达式

    一.初识lambda表达式 1.定义   lambda表达式是一个可传递的代码块,或者更确切地说,可以把lambda表达式理解为简洁地表示可传递的匿名方法的一种方式.它没有名称,但它有参数列表.函数主 ...

  2. Java核心技术-接口、lambda表达式与内部类

    本章将主要介绍: 接口技术:主要用来描述类具有什么功能,而并不给出每个功能的具体实现.一个类可以实现一个或多个接口. lambda表达式:这是一种表示可以在将来的某个时间点执行的代码块的简洁方法. 内 ...

  3. Upgrading to Java 8——第一章 Lambda表达式

    第一章 Lambda表达式 Lamada 表达式是Java SE 8中最重要的新特性,长期以来被认为是在Java中缺失的特性,它的出现使整个java 语言变得完整.至少到目前,在这节中你将学习到什么是 ...

  4. Java函数式编程和lambda表达式

    为什么要使用函数式编程 函数式编程更多时候是一种编程的思维方式,是种方法论.函数式与命令式编程的区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做.说白了,函数式编程是基于 ...

  5. Java 8 中的 Lambda 表达式

    Lambda 表达式是 Java 8 最受欢迎的功能.人们将函数式编程的概念引入了 Java 这门完全面向对象的命令式编程语言. 关于函数式编程是如何运作的,这个话题超出了本文的范围,不过我们会提炼出 ...

  6. Java 8新增的Lambda表达式

    一. 表达式入门 Lambda表达式支持将代码块作为方法参数,lambda表达式允许使用更简洁的代码来创建只有一个抽象方法的接口(这种接口被称为函数式接口)的实例,相当于一个匿名的方法. 1.1 La ...

  7. Java基础教程:Lambda表达式

    Java基础教程:Lambda表达式 本文部分内容引用自OneAPM:http://blog.oneapm.com/apm-tech/226.html 引入Lambda Java 是一流的面向对象语言 ...

  8. Java 8 (2) 使用Lambda表达式

    什么是Lambda? 可以把Lambda表达式理解为 简洁的表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表.函数主体.返回类型,可能还有一个可以抛出的异常列表. 使用Lambda可以让你更 ...

  9. java函数式编程之lambda表达式

    作为比较老牌的面向对象的编程语言java,在对函数式编程的支持上一直不温不火. 认为面向对象式编程就应该纯粹的面向对象,于是经常看到这样的写法:如果你想写一个方法,那么就必须把它放到一个类里面,然后n ...

随机推荐

  1. 裸辞两个月,海投一个月,从Android转战Web前端的求职之路

    前言 看到这个标题的童鞋,可能会产生两种想法: 想法一:这篇文章是标题党 想法二:Android开发越来越不景气了吗?前端越来越火了吗? 我一向不喜欢标题党,标题中的内容是我的亲身经历.我是2016年 ...

  2. 《网络》:设置三个密码:通过console口连接设备,进入特权模式,登录Telnet

    软件:Cisco Packet Tracer Instructor 软件下载链接在上一篇文章中. 内容:通过设置三个密码,熟悉采用Telnet方式配置交换机的方法. 细节说明:计算机的IP地址和交换机 ...

  3. 从PRISM开始学WPF(八)導航Navigation?

    0x6Navigation Basic Navigation Prism中的Navigation提供了一种类似导航的功能,他可以根据用户的输入,来刷新UI. 先看一个最简单的例子,通过按钮来导航到一个 ...

  4. 阿里云API网关(5)用户指南(调用 API)

    网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...

  5. MySql入门(2-2)创建数据库

    mysql -u root -p; show databases; create database apigateway; use apigateway; show tables;

  6. IPv6原理、应用与实践

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 作者:腾讯微信技术架构部团队 2017年11月26日,中共中央办公厅和国务院办公厅印发了<推荐互联网协议第六版(IPv6)规模部署行动 ...

  7. mysql解压缩版本的安装、初始化等

    https://dev.mysql.com/doc/refman/5.7/en/windows-install-archive.html 启动或者暂停mysql服务: https://dev.mysq ...

  8. 处理异常、常用类、反射、类加载与垃圾回收、java集合框架

    异常处理概述 检查异常:检查异常通常是用户错误或者不能被程序员所预见的问题.(cheched) 运行时异常:运行时异常是一个程序在运行过程中可能发生的.可以被程序员避免的异常类型.(Unchecked ...

  9. MyBatis(2)——MyBatis 深入学习

    编写日志输出环境配置文件 在开发过程中,最重要的就是在控制台查看程序输出的日志信息,在这里我们选择使用 log4j 工具来输出: 准备工作: 将[MyBatis]文件夹下[lib]中的 log4j 开 ...

  10. [LeetCode] Out of Boundary Paths 出界的路径

    There is an m by n grid with a ball. Given the start coordinate (i,j) of the ball, you can move the ...