《Jakarta Commons cookbook读书笔记》系列文章
3 Commons Collections v3.0
功能说明:增强java的泛型框架,引入函子的概念。
主要功能:增加了一些函子的接口以及一些实现。包括一些实现了 Comparator的类 ,封装了条件和判别式的Predicate接口,实现对象转换的Transformer接口以及模拟闭包的接口Closure;另外还有对jdk泛型框架的扩展。
概念介绍:
函子(functor):执行操作或功能的部件。例如java.util.Comparator和java.util.Iterator。他们都用于隔离算法。
此次文章篇幅较长,读者可以选择着重阅读斜体和着色文字,代码部分可以选择阅读。
3.1 Comparator的扩展
3.1.1 使用ReverseComparator实现反顺序排列。
排序前
Book book
|--List authors
|--[0]->Person person1
|--String name->"LiLei"
|--[1]->Person person2
|--String name->"Ark"
|--[2]->Person person3
|--String name->"HanMeimei"
import org.apache.commons.collections.comparators.ReverseComparator; Comparator nameComparor=new org.apache.commons.beanutils.BeanComparator("name"); Comparator reverseComparator=new ReverseComparator(nameComparor); Collections.sort(book.getAuthors(),reverseComparator);
按name属性反向排序后
Book book
|--List authors
|--[0]->Person person1
|--String name->"LiLei"
|--[1]->Person person2
|--String name->"HanMeimei"
|--[2]->Person person3
|--String name->"Ark"
通常情况下,如果只有一个Comparator。ReverseComparator显得有些鸡肋,因为可以通过Arrays.reverse()和Collections.reverse()将数组或者List反转。但是如果有多个Comparator,它的意义就显现出来了。
3.1.2 ComparatorChain结合多个Comparator进行排序
import org.apache.commons.collections.comparators.ComparatorChain; Comparator nameComparor=new org.apache.commons.beanutils.BeanComparator("name"); Comparator ageComparator=new org.apache.commons.beanutils.BeanComparator("age"); ComparatorChain comparatorChain=new ComparatorChain(); comparatorChain.addComparator(nameComparor); comparatorChain.addComparator(ageComparator); Collections.sort(book.getAuthors(),comparatorChain);
先加入的Comparator拥有较高优先级。上面例子中20岁的Auther会排在18岁的Ben前面,而相同的名字则年轻的会排在前面。
3.1.3 使用NullComparator包装Comparator,控制对null的排序
import org.apache.commmons.collections.comparators.NullComparator; //第二个参数为false,则name属性为null的值排在非null的前面; //如果为true,则反之。如果不加第二个参数,则默认为true; Comparator nullComparator =new NullComparator(nameComparator,false);
3.1.4 使用FixedOrderComparator执行固定顺序的排序
public class PokerCard{ private String value; private String suit; ... }
import org.apache.commons.collections.comparators.FixedOrderComparator //52张扑克牌从小到大排序例子 String[] suitOrder=new String{"Diamond","Club","Heart","Spade"}; String[] valueOrder=new String{"2","3","4","5","6","7","8","9","10","J","Q","K","A"} Comparator suitComparator=new FixedOrderComparator(suitOrder); suitComparator=new BeanComparator("suit",suitComparator); Comparator valueComparator=new FixedOrderComparator(valueOrder); valueComparator=new BeanComparator("value",valueComparator); Comparator comparatorChain=new ComparatorChain(); comparatorChain.add(suitComparator); comparatorChain.add(valueComparator); Collections.sort(pokerCardList,comparatorChain);
3.2 使用Predicates封装条件或者判别式
以下所有的类都继承org.apache.commons.collections.Predicate接口,而且该接口只有一个方法evaluate(Object)
package org.apache.commons.collections; public interface Predicate { public boolean evaluate(Object object); }
import org.apache.commons.collections.Predicate; Predicate isHeis=new EqualsPredicate("Heis"); Predicate notHeis=new NotPredicate(isHeis); Predicate nullIsTruePredicate=new NullIsTruePredicate(isHeis); Predicate instanceOfPredicate =new InstanceOfPredicate(String.class); isHeis.evaluate("Heis");->true notHeis.evaluate("His");->true nullIsTruePredicate.evaluate(null);->true nullIsTruePredicate.evaluate("Heis");->true instanceOfPredicate.evaluate("Heis");->true
3.2.1 复合Predicate实现复杂的条件逻辑
AndPredicate and关系
OrPredicate or关系
AllPredicate 条件之间为and关系
OnePredicate 当只有一个条件为true时,返回true
AnyPredicate 条件之间为or关系
Predicate isHeis=new EqualsPredicate("Heis"); Predicate isNotNull=NotNullPredicate.INSTANCE; Predicate isMale=new EqualsPredicate("male"); Predicate andPredicate=new AndPredicate(isHeis,isNotNull); Predicate orPredicate=new OrPredicate(isHeis,isNotNull); Predicate[] predicates=new Predicate[]{isHeis,isNotNull,isMale}; Predicate allPredicate=new AllPredicate(predicates); Predicate onePredicate=new OnePredicate(predicates);
3.3 利用Transformer实现对象转换
Transformer接口只有一个方法transform(),其设计的目的就是进行对象的转换,接受一个对象并据此创建一个新对象。
package org.apache.commons.collections; public interface Transformer { public Object transform(Object input); }
import org.apache.commons.collections.Transformer; //大黄蜂变形器 Transformer BumblebeeTrans=new Transform(){ public Object transform(Object input){ if(input instanceof BumblebeeRobot){ return new BumblebeeCar(input); }else{ ... } } } //大黄蜂机器人模式转换为汽车模式 BumblebeeCar car=BumblebeeTrans.transform(BumblebeeRobot.getInstance());
3.3.1 使用ChainedTransformer实现转换链
import org.apache.commons.collections.functors.ChainedTransformer; Transformer[] chainElements=new Transformer[]{transformer1,transformer2}; Transformer chain=new ChainedTransformer(chainElements); Object transformedResult=chain.transform(input);
3.3.2 结合Predicate和Transformer实现有条件的转换
import org.apache.commons.collections.functors.SwitchTransformer; Transformer defaultTransformer; Transformer[] tArray=new Transformer[]{t1,t2}; Predicate[] pArray=new Predicate[]{p1,p2}; Transformer st=new SwitchTransformer(tArray,pArray,defaultTransformer); //如果p1为true,则执行t1;如果p2为true,则执行t2;否则执行defaultTransformer Object tranformedResult=st.transform(input);
3.4 模拟闭包的接口Closure
package org.apache.commons.collections; public interface Closure { public void execute(Object input); }
3.4.1 实现一个给商品价格打9折的Closure
Closure discountClosure=new Closure(){ public void execute(Object input){ Product p=(Product)input; p.setPrice(p.getPrice()*0.9); } }
3.4.2 使用ChainedClosure链接多个Closure
import org.apache.commons.collections.functors.ChainedClosure; //对商品打九折,打包好后送达客户 Closure cArray=new Closure[]{discountClosure,packageClosure,postClosure}; Closure process=new ChainedClosure(cArray); process.execute(product);
3.4.3 使用IfClosure模拟条件语句
import org.apache.commons.collections.functors.IfClosure; Predicate isDiscountProduct=new Predicate(){ public boolean evaluate(Object object){ Product p=(Product)input; return p.isDiscountProduct(); } } //如果是折扣商品则打折出售(执行discountClosure.execute()), //否则原价出售(执行noDiscountClosure.execute())。 Closure discountAction=new IfColsure(isDiscountProduct,discountClosure,noDiscountClosure); discountAction.execute(product);
因为IfClosure构造函数接受Closure作为参数,所以IfClosure还可以嵌入其他IfClosure
3.4.4 使用WhileClosure,ForClosure模拟循环语句
//判断是否库存过多 Predicate isSurplus=new Predicate(){ public boolean evaluate(Object object){ Product p=(Product)input; return p.isSurplus(); } } //如果库存过多,继续打折,直至库存不在富余 Closure getItCheap=new WhileClosure(isSurplus,discountClosure); getItCheap.execute(product); //对商品进行3次打折 Closure getItCheap=new ForClosure(3,discountClosure); getItCheap.execute(product);