欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

[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.Consumerjava.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'