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

[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
@FunctionalInterface
public interface ConsumerTwo<T, T2> {
    public void accept(T t, T2 t2);
}
  • FunctionTwo
@FunctionalInterface
public interface FunctionTwo<T, T2, R> {
    public R apply(T t, T2 t2);
}

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

代码:Main类

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

  • 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) -> {
            // here is business rule logical
            System.out.println("here is business rule logical 1.");
        }, Arrays.asList(name, value));
    }
    
    /*
     * This is a consumer with exception sample
     */
    public void businessRuleTwoThrowException(final String name, final String value) {
        
        CodeShapePattern.consumerShape.accept((o) -> {
            // here is business rule logical
            System.out.println("here is business rule logical 2.");
            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) -> {
            // here is business rule logical
            System.out.println("here is business rule logical 3.");
            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 ----");
        }
        catch (Exception e) {
            System.out.println(MessageFormat.format("error method ''{0}'': {1}", method, e.getMessage()));
            throw e;
        }
        finally {
            System.out.println(MessageFormat.format("end method ''{0}''", method));
        }
    };
    
    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 ----");
            }
            catch (Exception e) {
                System.out.println(MessageFormat.format("error method ''{0}'': {1}", method, e.getMessage()));
                throw e;
            }
            finally {
                System.out.println(MessageFormat.format("end method ''{0}'', return ''{1}''", method, ret.toString()));
            }
            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) -> {
            // here is business rule logical
            System.out.println("here is business rule logical 1.");
        }, Arrays.asList(name, value));
    }
  • 代码:Code Shape 设计模式 - Consumer 我们可以看到,consumerShape 是一个静态变量,实现了统一的功能。 这个 consumerShape 使用了一个嵌套的 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 ----");
        }
        catch (Exception e) {
            System.out.println(MessageFormat.format("error method ''{0}'': {1}", method, e.getMessage()));
            throw e;
        }
        finally {
            System.out.println(MessageFormat.format("end method ''{0}''", method));
        }
    };

简化版:

    public static ConsumerTwo<Consumer<Object>, List<Object>> consumerShape = (body, params) -> 
    {
        try {
            body.accept(null);
        }
        catch (Exception e) {
            throw e;
        }
        finally {
        }
    };

代码说明 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) -> {
            // here is business rule logical
            System.out.println("here is business rule logical 3.");
            return name + " " + value;
        }, Arrays.asList(name, value));
    }
  • 代码:Code Shape 设计模式 - Function 不同于consumerShape, getFunctionShape 是一个静态泛型方法,实现了统一的功能。 这个 getFunctionShape 使用了一个嵌套的 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 ----");
            }
            catch (Exception e) {
                System.out.println(MessageFormat.format("error method ''{0}'': {1}", method, e.getMessage()));
                throw e;
            }
            finally {
                System.out.println(MessageFormat.format("end method ''{0}'', return ''{1}''", method, ret.toString()));
            }
            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;
            }
            finally {
            }
            return ret;
        };
        
        return function;
    }

输出结果

======== 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' ```

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏xx_Cc的学习总结专栏

iOS底层原理总结 - 探寻block的本质(二)

2884
来自专栏服务端技术杂谈

Java编码规范

命名 类名使用UpperCamelCase风格。 领域模型相关命名:DO / DTO / VO / DAO等。 方法名,参数名,成员变量,局部变量都统一使用lo...

3224
来自专栏逆向与安全

从虚拟机角度看Java多态->(重写override)的实现原理

工具与环境: Windows 7 x64企业版 Cygwin x64 jdk1.8.0_162 openjdk-8u40-src-b25-10_feb_201...

1770
来自专栏Java3y

Object对象你真理解了吗?

2769
来自专栏项勇

笔记10 | 学习整理静态static 和 终态final

1365
来自专栏小灰灰

JDK容器学习之Queue: ArrayDeque

数组双端队列 ArrayDeque 双端队列,表示可以添加元素到(或删除,获取)队列头也可以添加元素到(或删除,获取)队列尾 ? 1. 底层数据结构 类中定义成...

2036
来自专栏菜鸟计划

javascript 闭包详解

一、什么是匿名函数 创建一个函数并将它赋值给变量functionName,这种情况下创建的函数,即匿名函数。(函数表达式就是匿名函数) 二、闭包 1.什么是闭包...

3447
来自专栏博客园

Core官方DI解析(3)-ServiceCallSite

上一篇说过在整个DI框架中IServiceProviderEngine是核心,但是如果直接看IServiceProviderEngine派生类其实看不出也没什么...

902
来自专栏逸鹏说道

Python3 与 C# 基础语法对比(List、Tuple、Dict专栏)

Python3 与 C# 基础语法对比(基础知识场):https://www.cnblogs.com/dotnetcrazy/p/9102030.html

903
来自专栏老九学堂

十七个C语言新手编程时常犯的错误及解决方式

编译程序把a和A认为是两个不同的变量名,而显示出错信息。C认为大写字母和小写字母是两个不同的字符。习惯上,符号常量名用大写,变量名用小写表示,以增加可读性。

1574

扫码关注云+社区

领取腾讯云代金券