策略模式在实际项目中的应用二

****测试demo    git仓库地址:https://github.com/alwaysInRoad/test-strategy-demo2.git

                          csdn下载地址:https://download.csdn.net/download/weixin_40841731/10711655

该测试demo为普通项目,导入build path一下lib目录下的jar包,然后运行测试类即可在控制台看到测试结果

说明:

         本篇博客是建立在实际项目开发。在项目中应用策略模式,分享出来,希望小伙伴们能快速上手策略模式,并能在项目中优化自己的业务。

 

业务场景:在开发公司框架时,由于该框架省去了实体类,mapper,mapper.xml、部分service类和controller类,都用统一执行sql方法和统一返回结果。让开发人员只专注于写sql。 这样一来,关于参数的校验,校验方式,校验类型,校验结果,都得存于数据库,然后在统一执行sql的controller层,根据sql,及替换sql内的参数值,实现参数校验。

例如:数据库中存储这样一条sql:insert into t_role(role_id,role_name) values(#{id},${role_name})

          另一张参数的校验表中:格式可能是这样的。

          

在项目实际 运行过程中,因为同一在一个地方执行sql。我们是不能预知用户具体操作是什么,所以不像具体的一个表对应一个实体类,一个mapper类,一个service类,一个controller类,可以具体的制定错误信息。所以此处就很好的利用了策略模式+反射。根据 用户行为,反射生成策略对象,从而得到想要的结果。

 

代码部分:

1、公共校验接口类: ParamValidate.java  (每一个具体校验都实现此接口)

/**
 * 参数校验接口类
 * @author zr
 * @param param 校验参数
 * @param validateVal 参数值
 * @date 2018-9-17
 */
public interface ParamValidate {
      //校验方法,
	String validate(String param,String validateVal);

}

 

2、具体校验类: 例如校验邮箱的:IsEmail.java

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 邮箱校验
 * @author zr
 * @date 2018-9-17
 *
 */
public class IsEmail implements ParamValidate{

	@Override
	public String validate(String param,String validateVal) {
		String str = "^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$";
		Pattern p = Pattern.compile(str);
		Matcher m = p.matcher(param);
		if (m.matches() == false) {
			return "邮箱格式不正确";
		} else {
			return null;
		}
	}

}

还有其它校验类,这里不一 一列举。看截图

 

3、策略类:ParamValidateStrategy.java

/**
 * 参数校验策略类
 * @author zr
 * @date 2018-9-17
 *
 */
public class ParamValidateStrategy {
	//持有的具体策略的对象
	private ParamValidate paramValidate;
	/**
     * 构造函数,传入一个具体策略对象
     * @param dbPathSub    具体策略对象
     */
	public ParamValidateStrategy(ParamValidate paramValidate) {
		super();
		this.paramValidate = paramValidate;
	}
	 /**
     * 策略方法
     */
	public String validate(String param,String validateVal){
		return paramValidate.validate(param,validateVal);
	}

}

4、在具体的 业务类 业务处理部分,就是策略选择部分。

我是把具体业务抽离出来写了个工具类 ParamValidateUtil .java

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.collections.IteratorUtils;
import com.common.check.ParamValidate;
import com.common.check.ParamValidateStrategy;
import com.model.TAiSqlParam;
import net.sf.json.JSONObject;

/**
 * 校验类
 * @author zr
 * @date 2018年9月17日
 */
public class ParamValidateUtil {
	 /**
	  * 
	  * @author zhurun  
	  * @date 2018年9月17日
	  * @param @param TAiSqlParamList 
	  * @param @param keyParameter
	  * @param @return
	  * @param @throws ClassNotFoundException
	  * @param @throws InstantiationException
	  * @param @throws IllegalAccessException
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	  */
	 public static List<String> ValidateAllFields(List<TAiSqlParam> TAiSqlParamList,String keyParameter) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException  {
		 JSONObject json = JSONObject.fromObject(keyParameter);
		  //获得json数组的所有key
		  Iterator keys = json.keys();
		  List<String> keylist = IteratorUtils.toList(keys);
		  //错误信息集合
		  List<String> errorMsgList = new ArrayList<>();
		  for (TAiSqlParam tAiSqlParam : TAiSqlParamList) {
			  if(keylist.contains(tAiSqlParam.getKey())){
				 String paramValue = json.getString(tAiSqlParam.getKey());
				 //TODO: 此处待完善
				 //反射获取枚举类
				 Class<Enum> clazz = (Class<Enum>)Class.forName("com.common.Constant$ParamValidate");
				 //获取所有枚举实例
				 Enum[] enumConstants = clazz.getEnumConstants();
				 //根据方法名获取方法
				 //根据方法名获取方法
				 Method getDesc = clazz.getMethod("getDesc");
				 Method getIndex = clazz.getMethod("getIndex");
				 String validateType = null;
				 for (Enum enum1 : enumConstants) {
					 //判断枚举值与数据库中存的检查类型是否一致,一致就校验,不一直跳过
					 if(getIndex.invoke(enum1).equals(tAiSqlParam.getValidateType())){
						//执行枚举方法获得枚举实例对应的值
						 validateType  = (String)getDesc.invoke(enum1);
						 break;
					 }else{
						 continue;
					 }
				 }
				 if(validateType==null){
					 return "校验类型不存在!";
				 }
				 //根据数据库中储存的枚举类型,根据枚举值获取对应的枚举描述,从而反射生成校验类(校验类的类名与枚举描述必须一致)
			     Class<?> forName = Class.forName("com.common.check."+validateType);
				 Object obj = forName.newInstance();
				 ParamValidateStrategy	paramValidateStrategy = new ParamValidateStrategy((ParamValidate) obj);		 
				 String message = paramValidateStrategy.validate(paramValue,tAiSqlParam.getValidateVal());
				 errorMsgList.add(message);
			  }
		  }
		 return errorMsgList;
	 }
}

调用工具类的地方:

//获取参数key的字符串值,需要转换成json对象(需要替换sql中的数据)
String keyParameter = request.getParameter(KEY_PARAM);
//根据code得到sql Id
String tAiSqlId = tAiSqlMapper.getTAiSqlIdByCode(code);
//根据sql id得到参数验证list
List<TAiSqlParam> TAiSqlParamList = tAiSqlParamMapper.selectEntitySet(tAiSqlId);
//校验参数 keyParameter是前端传过来的
String message = ParamValidateUtil1.ValidateAllFields(TAiSqlParamList,keyParameter);

ParamValidateUtil 类中所用到的枚举类:Constant.java

/**
	  * 参数校验枚举类
	  * @author zr
	  * @date 2018年9月17日
	  */
	 public static enum ParamValidate {
		 CheckLength("checkLength",0),
		 IsAccId("IsAccId",1),
		 IsAge("IsAge",2),
		 IsEmail("IsEmail",3),
		 IsIdCard("IsIdCard",4),
		 IsPhoneNo("IsPhoneNo",5),
		 IsPostCode("IsPostCode",6),
		 IsPwd("IsPwd",7);
		 // 成员变量
         private String desc;
         private int index;

         // 构造方法
         private ParamValidate(String name, int index) {
             this.desc = name;
             this.index = index;
         }

         // 覆盖方法
         @Override
         public String toString() {
             return this.index + "_" + this.desc;
         }

		 public String getDesc() {
		  	 return desc;
		 }

		 public void setDesc(String desc) {
			 this.desc = desc;
		 }

		 public int getIndex() {
			 return index;
		 }

		 public void setIndex(int index) {
			 this.index = index;
		 }
	 } 

ParamValidateUtil 类中所用到的参数实体类:SqlParam.java

public class SqlParam {
    private String id;

    private String key;

    private String sqlId;

    private String validateType;

    private String validateVal;

    private String errorMsg;

    get和set方法略
}

总结:我个人理解,策略模式其实就是,利用一个中间类:策略类。来连接策略对象与业务类。策略类不知道业务类用什么策略对象,策略类也不知道具体调什么策略对象,策略类只是拥有父接口对应及调用父接口的方法。这就起到了解耦的作用。 当业务类指定具体策略对象,传给策略类,策略类就知道想要调用的策略对象了。

 

结语:本人所有文章都立志写的简单易懂,戳中问题点。 当然了,简单的同时可能忽略了很多细节与详细,如有不足的地方,还请谅解并指出。  如对文章或实现技术上有问题,可联系我:qq: 1226500260     邮箱:654868284@qq.com

 

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值