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代码:

Fun论设计模式之4:标准模式(Criteria Pattern)
  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 }
View Code

   以及部分Criteria代码:

Fun论设计模式之4:标准模式(Criteria Pattern)
  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 {@link}0haizhu0@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 {@link}0haizhu0@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     }
View Code

  这些代码,都是在内部运算数据然后返回引用本身(如何解决),使得方法可以像做数学公式一样进行运算,过滤(或者说改变)数据流,Spark的RDD就是受了这个设计模式的启发,在action触发之前,运行的函数本身不会对数据流运算,不过内部会标记数据流需要进行的运算,这也是标准模式的运用。

Fun论设计模式之4:标准模式(Criteria Pattern)

图1.像不像标准模式的过滤数据流?

上一篇:php – Doctrine ORM Criteria – 动态orX


下一篇:java – 使用Hibernate Criteria查询ManyToMany关系