• [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'

  • 相关阅读:
    [刘阳Java]_JdbcTemplate用法_第11讲
    [刘阳Java]_Spring对Dao的支持_第10讲
    [刘阳Java]_Spring AOP基于XML配置介绍_第9讲
    [刘阳Java]_Spring AOP注解详细介绍_第8讲
    [刘阳Java]_Spring AOP入门_第7讲
    [刘阳Java]_Spring常用注解介绍_第6讲
    [刘阳Java]_Spring相关配置介绍_第5讲
    [刘阳Java]_了解BeanFactory_第4讲
    vue传参
    axios的增删改查。
  • 原文地址:https://www.cnblogs.com/steven-yang/p/8948465.html
Copyright © 2020-2023  润新知