Java设计模式 粒子-流模式

写在前面的话:

其实这个模式的名字是我瞎想的,因为它的功能与名字的概念很相似,稍后详细介绍一下这种模式是怎样的设计思路。

一、设计思路

    农民伯伯获取农产品的方式有很多种,有些人先选水资源丰富的地方,先犁田,再灌水,种水稻,再杀虫,再收割,晾晒,脱壳。有些人选择种大豆,在田埂或者近水源的地方,耕地,种大豆,浇水,杀虫,收大豆。(只是举例子,肯定流程有不对的地方,就不要纠结了)。那么这些工作都有同样一个特点:在一条流程中间分布着很多步骤,每一个步骤承上启下,各个流程之间互不干扰,但是流程的步骤可能有相似的地方,通常我们写代码也是这样,一个流程一个流程从开始到结束的写,流程中间有相似的流程步骤,但是由于参数或者其他业务原因,没有复用到这些步骤,很多代码虽然不是重复代码,但是实现的作用是一样的,导致开发效率低下,那么粒子-流模式的设计思路就可以解决这种问题。

    粒子-流模式,流代表流程,粒子代表流程中的步骤,流由粒子组装而成,不同的粒子可以组装成不同的流,就跟积*木一样,千变万化,最重要的是,粒子可以绝对复用,当然,还是得靠代码写得好。

二、粒子-流模式的基类

    这个模式的基类有很多种,现在以能实现这种模式的最简单的方式来说一下:

    1.参数基类:

        为了保证粒子在所有流中都通用,所有的出入参数都将继承一个参数基类,另外,流中可能需要记录一些其他信息,因为还需要一个上下文基类。

    2.粒子基类:

        每一个粒子类都将继承粒子基类,那么所有流在加载粒子类时,就可以达到通用的目的。

    3.流基类:

        流基类用以加载粒子类,我们使用流执行器类执行粒子类,规定了一些规范,以便流执行类更好的执行。

    4.流执行器:

        根据流类提供的规范执行粒子类。

    以上就是实现最简单的粒子-流模式的四个基类了。

三、代码实现

    我们先定义一个最基本的类:BaseDataType,它提供三个方法:是否包含属性,获取属性,设置属性,这样子类可以在不强转的情况下可以直接获取和设置属性值。所有基类都可以继承这个类,代码实现:

package com.yhd.shaoyu.onlineconfig.vo;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Description:
 * @Author: shaoyu1
 * @Date Create in 2018/8/2 15:20
 */
public class BaseDataType implements Serializable {
    /**
     * 是否包含属性
     * @param filedname
     * @return
     */
    public boolean containsProperty(String filedname){
        try{
            return this.getClass().getDeclaredField(filedname)!=null;
        }catch (NoSuchFieldException e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 获取属性(有默认值) 当没有这种属性时,返回默认值
     * @param filedName
     * @param def
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public Object get(String filedName,Object def) throws  InvocationTargetException, IllegalAccessException {
        if(containsProperty(filedName)){
            return get(filedName)==null?def:get(filedName);
        }else {
            return def;
        }
    }

    /**
     * 获取属性
     * @param filedName
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public Object get(String filedName) throws  InvocationTargetException, IllegalAccessException {
        if(!containsProperty(filedName)){
            return null;
        }else{
            try{
                return getPropertyGetMethod(this.getClass(),filedName).invoke(this);
            }catch (NullPointerException  e){
                throw new RuntimeException("属性"+filedName+"没有对应的get方法");

            }
        }
    }

    /**
     * 设置属性
     * @param filedName
     * @param property
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public void set(String filedName,Object property)throws  InvocationTargetException, IllegalAccessException {
        if(!containsProperty(filedName)){
            throw new RuntimeException("没有对应的属性:"+filedName);
        }else {
            try{
                getPropertySetMethod(this.getClass(),filedName).invoke(this,property);
            }catch (NullPointerException e){
                throw new RuntimeException("属性"+filedName+"没有对应的set方法");
            }
        }
    }

    private Method getPropertyGetMethod(Class<?> type, String filedName) {
        Method[] methods = type.getMethods();
        for (Method method : methods) {
            if (method.getParameterTypes().length != 0)
                continue;

            if (method.getName().equalsIgnoreCase("get" + filedName)) {
                return method;
            }

            if ((Boolean.class.isAssignableFrom(method.getReturnType()) || "boolean".equals(method.getReturnType().getName())) && method.getName().equalsIgnoreCase("is" + filedName)) {
                return method;
            }
        }
        return null;
    }
    private Method getPropertySetMethod(Class<?> type, String filedName) {
        Method[] methods = type.getMethods();
        for (Method method : methods) {
            if (method.getParameterTypes().length != 1)
                continue;
            if (method.getName().equalsIgnoreCase("set" + filedName)) {
                return method;
            }
            if ((Boolean.class.isAssignableFrom(method.getParameterTypes()[0]) || "boolean".equals(method.getParameterTypes()[0].getName())) && method.getName().equalsIgnoreCase("set" + filedName.replace("is", ""))) {
                return method;
            }
        }
        return null;
    }
}

然后我们再定义一下request和response以及context基类:

package com.yhd.shaoyu.onlineconfig.vo;

import com.alibaba.fastjson.JSON;

/**
 * @Description:
 * @Author: shaoyu1
 * @Date Create in 2018/8/2 15:51
 */
public class BaseRequest extends BaseDataType {


    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }

}
package com.yhd.shaoyu.onlineconfig.vo;

/**
 * @Description:
 * @Author: shaoyu1
 * @Date Create in 2018/8/2 16:06
 */
public class BaseResponse extends BaseDataType {

    public String code;
    public String msg;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
package com.yhd.shaoyu.onlineconfig.vo;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description:
 * @Author: shaoyu1
 * @Date Create in 2018/8/2 15:51
 */
public class BaseFlowContext extends BaseDataType {
    /**流程中断控制器*/
    private boolean skipException;
    /**上下文记录信息*/
    private Map<String,Object> attributes = new HashMap<>();
    /**流程走向*/
    private StringBuilder flow = new StringBuilder();

    public boolean isSkipException() {
        return skipException;
    }

    public void setSkipException(boolean skipException) {
        this.skipException = skipException;
    }
    /**获取上下文信息*/
    public Object getAttribute(String key){
        return attributes.get(key);
    }
    /**设置上下文信息*/
    public void setAttribute(String key,Object attr){
        if(attr==null){
            attributes.remove(key);
        }else{
            attributes.put(key,attr);
        }
    }
    public String getFlow(){
        return this.flow.toString();
    }
    /**记录流程走向*/
    public void putFlow(String className){
        if(flow.length()==0){
            this.flow.append(className);
        }else{
            this.flow.append("=>"+className);
        }
    }
}

然后就是流基类,流基类中有执行器类属性,还有三个abstract方法需要子类实现,另外还有doFlow方法是专门给业务类调用的,当然我这里写的很简单,只是将粒子分成了三个独立的小模块来先后执行,这里还可以写的更好,就不再赘述了:

package com.yhd.shaoyu.onlineconfig.flow;

import com.yhd.shaoyu.onlineconfig.flowExecutor.FlowExecutor;
import com.yhd.shaoyu.onlineconfig.vo.*;

import java.util.ArrayList;

/**
 * @Description:
 * @Author: shaoyu1
 * @Date Create in 2018/8/2 15:49
 */
public abstract class ServiceFlow<requestType extends BaseRequest,responseType extends BaseResponse> {
    FlowExecutor executor = FlowExecutor.getExecutor();


    public abstract ArrayList<BaseGranule> getPreGranule();
    public abstract ArrayList<BaseGranule> getPostGranule();
    public abstract ArrayList<BaseGranule> getAfterGranule();


    public responseType doFlow(requestType request, responseType response, BaseFlowContext context){
        try{
            executor.executeGraules("前置粒子处理",getPreGranule(),request,response,context);
            executor.executeGraules("主要流程粒子处理",getPostGranule(),request,response,context);
            executor.executeGraules("后置粒子处理",getAfterGranule(),request,response,context);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
        return response;
    }
}

粒子基类,粒子基类有一个属性step,是用于在流的一个模块中确认执行顺序的,还有两个方法,execute方式是真正做业务逻辑的地方,在子类中必须实现这个方法来写逻辑代码,而doFlow方法则是交给执行器类调用的:

package com.yhd.shaoyu.onlineconfig.vo;

/**
 * @Description:
 * @Author: shaoyu1
 * @Date Create in 2018/8/2 16:02
 */
public abstract class BaseGranule {

    private int step;

    public abstract void execute(BaseRequest request,BaseResponse response,BaseFlowContext context)throws Exception;

    public void doFlow(BaseRequest request,BaseResponse response,BaseFlowContext context) throws Exception {
        context.putFlow(this.getClass().getSimpleName());
        try{
            this.execute(request,response,context);
        }catch (Exception e){
            context.putFlow(this.getClass().getSimpleName()+"出错:"+e.getMessage());
            e.printStackTrace();
            throw e;
        }
    }

    public int getStep() {
        return step;
    }

    public void setStep(int step) {
        this.step = step;
    }
}

类执行器:

package com.yhd.shaoyu.onlineconfig.flowExecutor;

import com.yhd.shaoyu.onlineconfig.vo.BaseFlowContext;
import com.yhd.shaoyu.onlineconfig.vo.BaseGranule;
import com.yhd.shaoyu.onlineconfig.vo.BaseRequest;
import com.yhd.shaoyu.onlineconfig.vo.BaseResponse;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.List;

/**
 * @Description:
 * @Author: shaoyu1
 * @Date Create in 2018/8/2 16:10
 */
public class FlowExecutor<requestType extends BaseRequest,responseType extends BaseResponse> {

    private static FlowExecutor executor = new FlowExecutor();

    private FlowExecutor(){ super();}

    public static FlowExecutor getExecutor() {
        return executor;
    }

    public void executeGraules(String step, List<BaseGranule> granules, requestType request, responseType response, BaseFlowContext context){
        if(CollectionUtils.isEmpty(granules)){
            context.putFlow(step+"中,没有有效粒子");
        }else{
            BaseGranule[]baseGranules = granules.toArray(new BaseGranule[0]);
            Arrays.sort(baseGranules, (o1, o2) -> o1.getStep()-o2.getStep());
            for (BaseGranule granule:baseGranules) {
                if(context.isSkipException()){
                    context.putFlow("上下文终止流程继续进行..");
                    break;
                }
                try{
                    granule.doFlow(request,response,context);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        response.setMsg(context.getFlow());
    }

}

好了,基类就差不多写完了,下面说一个实例,就不贴全部代码了,直接贴粒子类:

粒子1,从request中获取用户名,查询用户信息放到response里去:

@Override
public void execute(BaseRequest request, BaseResponse response, BaseFlowContext context) throws Exception {
    response.set("user",BeanUtil.getBean(ConfigUserRepository.class).findConfigUserByUserName(request.get("userName","").toString()));
    //context.setSkipException(true);
}

粒子2,将response中的用户信息的用户名改成:

@Override
public void execute(BaseRequest request, BaseResponse response, BaseFlowContext context) throws Exception {
    TestResponse testResponse = (TestResponse) response;
    testResponse.getUser().setUserName("I had changed the username");
}

测试:

TestFlow flow = new TestFlow();
   TestRequest request = new TestRequest();
   request.setUserName("shaoyu");
   TestResponse response = new TestResponse();
   BaseFlowContext context = new BaseFlowContext();
   flow.doFlow(request,response,context);
   System.out.println(response.getUser().getUserName());
   System.out.println(response.getMsg());

结果:

I had changed the username

前置粒子处理中,没有有效粒子=>TestGranule=>TestGranule1=>后置粒子处理中,没有有效粒子

将粒子1中的注释代码放开再执行一遍:

shaoyu

前置粒子处理中,没有有效粒子=>TestGranule=>上下文终止流程继续进行..=>后置粒子处理中,没有有效粒子

 

转载于:https://my.oschina.net/siwcky90/blog/1926192

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值