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 
View Code

   以及部分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     
View Code

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

技术图片

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

以上是关于Fun论设计模式之4:标准模式(Criteria Pattern)的主要内容,如果未能解决你的问题,请参考以下文章

Fun论设计模式之3:外观模式(Facade Pattern)

Fun论设计模式之5:建造者模式(Builder Pattern)

Fun论设计模式之7:中介者模式(Mediator Pattern)

论特定场景适合的设计模式之1:简单工厂模式

过滤器模式

过滤器模式(Filter Pattern)