Fun论设计模式之4:标准模式(Criteria Pattern)
Posted dgutfly
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Fun论设计模式之4:标准模式(Criteria Pattern)相关的知识,希望对你有一定的参考价值。
标准模式,又叫过滤器模式(Filter Pattern),这个设计模式在我们常用的工具里面会大量体现,尤其是在数据处理方面,但我们却很难发现。
意图:允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。
主要解决:对象运算过程的直觉化。
何时使用:当您想让对象本身进行运算,并且方法可串一起运行。
如何解决:使用的方法在对象内部进行运算,改变内部数据,同时返回参与计算的对象本身,方便下一次引用计算。
关键代码:对象内部运算改变结果,返回对象引用本身。
Mybatis和hibernates如果要用Example直接生成一条SQL语句,中间肯定会使用createCriteria()和andNotEqualTo()之类的函数,前者还有类似于把不同criteria的条件进行并集(or())或交集(and(),createCriteria())操作;后者还可以是andIn()之类的子条件,组合在一起,成为一个criteria。
比如说使用tk.mybatis里面的包,建立查询语句:new Example(Student.class).createCriteria().andEqualTo("studentId",3303).andIn("classId",2,4,40).or().andEqualTo("name","funcfans"),这里实际上可以分成以下几条语句:
Example example = new Example(Student.class);
example.createCriteria().andEqualTo("studentId",3303).andIn("classId",2,4,40);
example.or().andEqualTo("name","funcfans")
组合成这样的SQL语句:select * from student where (studentId=3303 and classId in (2,4,40) ) or (name=‘funcfans‘)
这里就可以看出来,这个条件语句的拼接,或者说对数据的过滤流,就属于上面说的过滤器模式。example传入criteria过滤数据流,criteria传入各种数据和条件过滤数据流。(主要解决)
这里摘取部分Example代码:
1 package tk.mybatis.mapper.entity; 2 3 import org.apache.ibatis.reflection.MetaObject; 4 import org.apache.ibatis.reflection.SystemMetaObject; 5 import org.apache.ibatis.type.TypeHandler; 6 import tk.mybatis.mapper.MapperException; 7 import tk.mybatis.mapper.mapperhelper.EntityHelper; 8 import tk.mybatis.mapper.util.Sqls; 9 import tk.mybatis.mapper.util.StringUtil; 10 11 import java.util.*; 12 13 /** 14 * 通用的Example查询对象 15 * 16 * @author liuzh 17 */ 18 public class Example implements IDynamicTableName 19 protected String orderByClause; 20 21 protected boolean distinct; 22 23 protected boolean exists; 24 25 protected boolean notNull; 26 27 protected boolean forUpdate; 28 29 //查询字段 30 protected Set<String> selectColumns; 31 32 //排除的查询字段 33 protected Set<String> excludeColumns; 34 35 protected String countColumn; 36 37 protected List<Criteria> oredCriteria; 38 39 protected Class<?> entityClass; 40 41 protected EntityTable table; 42 //属性和列对应 43 protected Map<String, EntityColumn> propertyMap; 44 //动态表名 45 protected String tableName; 46 47 protected OrderBy ORDERBY; 48 49 /** 50 * 默认exists为true 51 * 52 * @param entityClass 53 */ 54 public Example(Class<?> entityClass) 55 this(entityClass, true); 56 57 58 /** 59 * 带exists参数的构造方法,默认notNull为false,允许为空 60 * 61 * @param entityClass 62 * @param exists - true时,如果字段不存在就抛出异常,false时,如果不存在就不使用该字段的条件 63 */ 64 public Example(Class<?> entityClass, boolean exists) 65 this(entityClass, exists, false); 66 67 68 /** 69 * 带exists参数的构造方法 70 * 71 * @param entityClass 72 * @param exists - true时,如果字段不存在就抛出异常,false时,如果不存在就不使用该字段的条件 73 * @param notNull - true时,如果值为空,就会抛出异常,false时,如果为空就不使用该字段的条件 74 */ 75 public Example(Class<?> entityClass, boolean exists, boolean notNull) 76 this.exists = exists; 77 this.notNull = notNull; 78 oredCriteria = new ArrayList<Criteria>(); 79 this.entityClass = entityClass; 80 table = EntityHelper.getEntityTable(entityClass); 81 propertyMap = table.getPropertyMap(); 82 this.ORDERBY = new OrderBy(this, propertyMap); 83 84 85 public Criteria or() 86 Criteria criteria = createCriteriaInternal(); 87 criteria.setAndOr("or"); 88 oredCriteria.add(criteria); 89 return criteria; 90 91 92 public Criteria createCriteria() 93 Criteria criteria = createCriteriaInternal(); 94 if (oredCriteria.size() == 0) 95 criteria.setAndOr("and"); 96 oredCriteria.add(criteria); 97 98 return criteria; 99 100 101 protected Criteria createCriteriaInternal() 102 Criteria criteria = new Criteria(propertyMap, exists, notNull); 103 return criteria; 104 105 106
以及部分Criteria代码:
1 protected abstract static class GeneratedCriteria 2 protected List<Criterion> criteria; 3 //字段是否必须存在 4 protected boolean exists; 5 //值是否不能为空 6 protected boolean notNull; 7 //连接条件 8 protected String andOr; 9 //属性和列对应 10 protected Map<String, EntityColumn> propertyMap; 11 12 protected GeneratedCriteria(Map<String, EntityColumn> propertyMap, boolean exists, boolean notNull) 13 super(); 14 this.exists = exists; 15 this.notNull = notNull; 16 criteria = new ArrayList<Criterion>(); 17 this.propertyMap = propertyMap; 18 19 20 protected void addCriterion(String condition) 21 if (condition == null) 22 throw new MapperException("Value for condition cannot be null"); 23 24 if (condition.startsWith("null")) 25 return; 26 27 criteria.add(new Criterion(condition)); 28 29 30 protected void addCriterion(String condition, Object value, String property) 31 if (value == null) 32 if (notNull) 33 throw new MapperException("Value for " + property + " cannot be null"); 34 else 35 return; 36 37 38 if (property == null) 39 return; 40 41 criteria.add(new Criterion(condition, value)); 42 43 44 protected void addCriterion(String condition, Object value1, Object value2, String property) 45 if (value1 == null || value2 == null) 46 if (notNull) 47 throw new MapperException("Between values for " + property + " cannot be null"); 48 else 49 return; 50 51 52 if (property == null) 53 return; 54 55 criteria.add(new Criterion(condition, value1, value2)); 56 57 58 protected void addOrCriterion(String condition) 59 if (condition == null) 60 throw new MapperException("Value for condition cannot be null"); 61 62 if (condition.startsWith("null")) 63 return; 64 65 criteria.add(new Criterion(condition, true)); 66 67 68 protected void addOrCriterion(String condition, Object value, String property) 69 if (value == null) 70 if (notNull) 71 throw new MapperException("Value for " + property + " cannot be null"); 72 else 73 return; 74 75 76 if (property == null) 77 return; 78 79 criteria.add(new Criterion(condition, value, true)); 80 81 82 protected void addOrCriterion(String condition, Object value1, Object value2, String property) 83 if (value1 == null || value2 == null) 84 if (notNull) 85 throw new MapperException("Between values for " + property + " cannot be null"); 86 else 87 return; 88 89 90 if (property == null) 91 return; 92 93 criteria.add(new Criterion(condition, value1, value2, true)); 94 95 96 public Criteria andIsNull(String property) 97 addCriterion(column(property) + " is null"); 98 return (Criteria) this; 99 100 101 public Criteria andIsNotNull(String property) 102 addCriterion(column(property) + " is not null"); 103 return (Criteria) this; 104 105 106 public Criteria andEqualTo(String property, Object value) 107 addCriterion(column(property) + " =", value, property(property)); 108 return (Criteria) this; 109 110 111 public Criteria andNotEqualTo(String property, Object value) 112 addCriterion(column(property) + " <>", value, property(property)); 113 return (Criteria) this; 114 115 116 public Criteria andGreaterThan(String property, Object value) 117 addCriterion(column(property) + " >", value, property(property)); 118 return (Criteria) this; 119 120 121 public Criteria andGreaterThanOrEqualTo(String property, Object value) 122 addCriterion(column(property) + " >=", value, property(property)); 123 return (Criteria) this; 124 125 126 public Criteria andLessThan(String property, Object value) 127 addCriterion(column(property) + " <", value, property(property)); 128 return (Criteria) this; 129 130 131 public Criteria andLessThanOrEqualTo(String property, Object value) 132 addCriterion(column(property) + " <=", value, property(property)); 133 return (Criteria) this; 134 135 136 public Criteria andIn(String property, Iterable values) 137 addCriterion(column(property) + " in", values, property(property)); 138 return (Criteria) this; 139 140 141 public Criteria andNotIn(String property, Iterable values) 142 addCriterion(column(property) + " not in", values, property(property)); 143 return (Criteria) this; 144 145 146 public Criteria andBetween(String property, Object value1, Object value2) 147 addCriterion(column(property) + " between", value1, value2, property(property)); 148 return (Criteria) this; 149 150 151 public Criteria andNotBetween(String property, Object value1, Object value2) 152 addCriterion(column(property) + " not between", value1, value2, property(property)); 153 return (Criteria) this; 154 155 156 public Criteria andLike(String property, String value) 157 addCriterion(column(property) + " like", value, property(property)); 158 return (Criteria) this; 159 160 161 public Criteria andNotLike(String property, String value) 162 addCriterion(column(property) + " not like", value, property(property)); 163 return (Criteria) this; 164 165 166 /** 167 * 手写条件 168 * 169 * @param condition 例如 "length(countryname)<5" 170 * @return 171 */ 172 public Criteria andCondition(String condition) 173 addCriterion(condition); 174 return (Criteria) this; 175 176 177 /** 178 * 手写左边条件,右边用value值 179 * 180 * @param condition 例如 "length(countryname)=" 181 * @param value 例如 5 182 * @return 183 */ 184 public Criteria andCondition(String condition, Object value) 185 criteria.add(new Criterion(condition, value)); 186 return (Criteria) this; 187 188 189 /** 190 * 手写左边条件,右边用value值 191 * 192 * @param condition 例如 "length(countryname)=" 193 * @param value 例如 5 194 * @param typeHandler 类型处理 195 * @return 196 * @deprecated 由于typeHandler起不到作用,该方法会在4.x版本去掉 197 */ 198 @Deprecated 199 public Criteria andCondition(String condition, Object value, String typeHandler) 200 criteria.add(new Criterion(condition, value, typeHandler)); 201 return (Criteria) this; 202 203 204 /** 205 * 手写左边条件,右边用value值 206 * 207 * @param condition 例如 "length(countryname)=" 208 * @param value 例如 5 209 * @param typeHandler 类型处理 210 * @return 211 * @deprecated 由于typeHandler起不到作用,该方法会在4.x版本去掉 212 */ 213 @Deprecated 214 public Criteria andCondition(String condition, Object value, Class<? extends TypeHandler> typeHandler) 215 criteria.add(new Criterion(condition, value, typeHandler.getCanonicalName())); 216 return (Criteria) this; 217 218 219 /** 220 * 将此对象的不为空的字段参数作为相等查询条件 221 * 222 * @param param 参数对象 223 * @author Bob @link0haizhu0@gmail.com 224 * @Date 2015年7月17日 下午12:48:08 225 */ 226 public Criteria andEqualTo(Object param) 227 MetaObject metaObject = SystemMetaObject.forObject(param); 228 String[] properties = metaObject.getGetterNames(); 229 for (String property : properties) 230 //属性和列对应Map中有此属性 231 if (propertyMap.get(property) != null) 232 Object value = metaObject.getValue(property); 233 //属性值不为空 234 if (value != null) 235 andEqualTo(property, value); 236 237 238 239 return (Criteria) this; 240 241 242 /** 243 * 将此对象的所有字段参数作为相等查询条件,如果字段为 null,则为 is null 244 * 245 * @param param 参数对象 246 */ 247 public Criteria andAllEqualTo(Object param) 248 MetaObject metaObject = SystemMetaObject.forObject(param); 249 String[] properties = metaObject.getGetterNames(); 250 for (String property : properties) 251 //属性和列对应Map中有此属性 252 if (propertyMap.get(property) != null) 253 Object value = metaObject.getValue(property); 254 //属性值不为空 255 if (value != null) 256 andEqualTo(property, value); 257 else 258 andIsNull(property); 259 260 261 262 return (Criteria) this; 263 264 265 public Criteria orIsNull(String property) 266 addOrCriterion(column(property) + " is null"); 267 return (Criteria) this; 268 269 270 public Criteria orIsNotNull(String property) 271 addOrCriterion(column(property) + " is not null"); 272 return (Criteria) this; 273 274 275 public Criteria orEqualTo(String property, Object value) 276 addOrCriterion(column(property) + " =", value, property(property)); 277 return (Criteria) this; 278 279 280 public Criteria orNotEqualTo(String property, Object value) 281 addOrCriterion(column(property) + " <>", value, property(property)); 282 return (Criteria) this; 283 284 285 public Criteria orGreaterThan(String property, Object value) 286 addOrCriterion(column(property) + " >", value, property(property)); 287 return (Criteria) this; 288 289 290 public Criteria orGreaterThanOrEqualTo(String property, Object value) 291 addOrCriterion(column(property) + " >=", value, property(property)); 292 return (Criteria) this; 293 294 295 public Criteria orLessThan(String property, Object value) 296 addOrCriterion(column(property) + " <", value, property(property)); 297 return (Criteria) this; 298 299 300 public Criteria orLessThanOrEqualTo(String property, Object value) 301 addOrCriterion(column(property) + " <=", value, property(property)); 302 return (Criteria) this; 303 304 305 public Criteria orIn(String property, Iterable values) 306 addOrCriterion(column(property) + " in", values, property(property)); 307 return (Criteria) this; 308 309 310 public Criteria orNotIn(String property, Iterable values) 311 addOrCriterion(column(property) + " not in", values, property(property)); 312 return (Criteria) this; 313 314 315 public Criteria orBetween(String property, Object value1, Object value2) 316 addOrCriterion(column(property) + " between", value1, value2, property(property)); 317 return (Criteria) this; 318 319 320 public Criteria orNotBetween(String property, Object value1, Object value2) 321 addOrCriterion(column(property) + " not between", value1, value2, property(property)); 322 return (Criteria) this; 323 324 325 public Criteria orLike(String property, String value) 326 addOrCriterion(column(property) + " like", value, property(property)); 327 return (Criteria) this; 328 329 330 public Criteria orNotLike(String property, String value) 331 addOrCriterion(column(property) + " not like", value, property(property)); 332 return (Criteria) this; 333 334 335 /** 336 * 手写条件 337 * 338 * @param condition 例如 "length(countryname)<5" 339 * @return 340 */ 341 public Criteria orCondition(String condition) 342 addOrCriterion(condition); 343 return (Criteria) this; 344 345 346 /** 347 * 手写左边条件,右边用value值 348 * 349 * @param condition 例如 "length(countryname)=" 350 * @param value 例如 5 351 * @return 352 */ 353 public Criteria orCondition(String condition, Object value) 354 criteria.add(new Criterion(condition, value, true)); 355 return (Criteria) this; 356 357 358 /** 359 * 将此对象的不为空的字段参数作为相等查询条件 360 * 361 * @param param 参数对象 362 * @author Bob @link0haizhu0@gmail.com 363 * @Date 2015年7月17日 下午12:48:08 364 */ 365 public Criteria orEqualTo(Object param) 366 MetaObject metaObject = SystemMetaObject.forObject(param); 367 String[] properties = metaObject.getGetterNames(); 368 for (String property : properties) 369 //属性和列对应Map中有此属性 370 if (propertyMap.get(property) != null) 371 Object value = metaObject.getValue(property); 372 //属性值不为空 373 if (value != null) 374 orEqualTo(property, value); 375 376 377 378 return (Criteria) this; 379 380 381 /** 382 * 将此对象的所有字段参数作为相等查询条件,如果字段为 null,则为 is null 383 * 384 * @param param 参数对象 385 */ 386 public Criteria orAllEqualTo(Object param) 387 MetaObject metaObject = SystemMetaObject.forObject(param); 388 String[] properties = metaObject.getGetterNames(); 389 for (String property : properties) 390 //属性和列对应Map中有此属性 391 if (propertyMap.get(property) != null) 392 Object value = metaObject.getValue(property); 393 //属性值不为空 394 if (value != null) 395 orEqualTo(property, value); 396 else 397 orIsNull(property); 398 399 400 401 return (Criteria) this; 402 403 404 public List<Criterion> getAllCriteria() 405 return criteria; 406 407 408 public String getAndOr() 409 return andOr; 410 411 412 public void setAndOr(String andOr) 413 this.andOr = andOr; 414 415 416 public List<Criterion> getCriteria() 417 return criteria; 418 419 420 public boolean isValid() 421 return criteria.size() > 0; 422 423 424 425 public static class Criteria extends GeneratedCriteria 426 427 protected Criteria(Map<String, EntityColumn> propertyMap, boolean exists, boolean notNull) 428 super(propertyMap, exists, notNull); 429 430
这些代码,都是在内部运算数据然后返回引用本身(如何解决),使得方法可以像做数学公式一样进行运算,过滤(或者说改变)数据流,Spark的RDD就是受了这个设计模式的启发,在action触发之前,运行的函数本身不会对数据流运算,不过内部会标记数据流需要进行的运算,这也是标准模式的运用。
图1.像不像标准模式的过滤数据流?
以上是关于Fun论设计模式之4:标准模式(Criteria Pattern)的主要内容,如果未能解决你的问题,请参考以下文章
Fun论设计模式之3:外观模式(Facade Pattern)
Fun论设计模式之5:建造者模式(Builder Pattern)