浏览 1919 次
锁定老帖子 主题:在java中小试FP(二)
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-02-29
以下代码是为了用200行以内的java代码实现一些functional programming的特性,并且可以直接用spring定义任意程序流程. User类是一个pojo UserHandler和UserValidator是包含一些业务逻辑的类,包含了一些业务方法, 包括一下方法 UserValidator.java boolean validate(User u); UserHandler.java User demoActionOne(User u); User demoActionTwo(User u); String getRole(User u); User makeTaller(User u); 现在可以直接通过对这些已经有的功能组合就能有新的功能,比如 这样的代码 User u = new User("gordon", 25, 173); UserValidator v=new UserValidator(); UserHandler h=new UserHandler(); if(v.validate(u)){ h.demoActionOne(u); }else{ h.demoActionTwo(u); } 可以这样写 Functor validate=Functor.define(new UserValidator(),"validate"); Functor actOne=Functor.define(new UserHandler(),"demoActionOne"); Functor actTwo=Functor.define(new UserHandler(),"demoActionTwo"); Functor newProcess=validate.sw(true,actOne,false,actTwo); User u = new User("gordon", 25, 173); newProcess.apply(u); 这里的newProcess就是一个新的程序流程(或者说片断), 也可以使用标准的spring xml定义作为程序流程定制 比如 <bean parent="define" id="validate"> <constructor-arg ref="userValidator"/> <constructor-arg value="validate"/> </bean> <bean parent="define" id="actOne"> <constructor-arg ref="userHandler"/> <constructor-arg value="demoActionOne"/> </bean> <bean parent="define" id="actTwo"> <constructor-arg ref="userHandler"/> <constructor-arg value="demoActionTwo"/> </bean> <bean id="process1" parent="choice"> <constructor-arg ref="userRoleEq2driver"/> <constructor-arg><map> <entry><key><value type="boolean">true</value></key><ref bean="actOne"/></entry> <entry><key><value type="boolean">false</value></key><ref bean="actTwo"/></entry> </map></constructor-arg> </bean> 仔细考虑一下,用fp做个简单的流程拼装器应该会比较简单。 把上次的代码稍微修改一下,再配上spring就马上可以订制流程咯。 测试代码 Test.java package com.gordon.functor.test; import com.gordon.functor.Functor; import com.gordon.functor.functors.EqualFunctor; import com.gordon.functor.legacy.User; import com.gordon.functor.legacy.UserHandler; import com.gordon.functor.legacy.UserValidator; import java.util.HashMap; import java.util.Map; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) throws Exception { User u1 = new User("gordon", 25, 173); User u2 = new User("jiacheng",25,173); ApplicationContext context = new ClassPathXmlApplicationContext( new String[] {"flow.xml"}); Functor process3=(Functor)context.getBean("process1"); process3.apply(u1); process3.apply(u2); System.out.println(); Functor p2=(Functor)context.getBean("p2"); p2.apply(u2); Functor p3=(Functor)context.getBean("setusername"); p3.apply("testname",u2); System.out.println(u2); Functor setUserNameToLarry=p3.curry("larry"); setUserNameToLarry.apply(u2); System.out.println(u2); } } 流程定义文件 flow.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <!--common settings--> <bean id="sequence" abstract="true" class="com.gordon.functor.Combinator" factory-method="sequence"/> <bean id="choice" abstract="true" class="com.gordon.functor.Combinator" factory-method="sw"/> <bean id="define" abstract="true" class="com.gordon.functor.Combinator" factory-method="define"/> <bean id="eq" class="com.gordon.functor.functors.EqualFunctor"/> <bean id="eq2" abstract="true" factory-bean="eq" factory-method="to"/> <!--old system module/class/function--> <bean id="userValidator" class="com.gordon.functor.legacy.UserValidator"/> <bean id="userHandler" class="com.gordon.functor.legacy.UserHandler"/> <!--new function based on functor which shouldn't be created,for demo only--> <bean parent="define" id="demoActionOne"> <constructor-arg ref="userHandler"/> <constructor-arg value="demoActionOne"/> </bean> <bean parent="define" id="demoActionTwo"> <constructor-arg ref="userHandler"/> <constructor-arg value="demoActionTwo"/> </bean> <!--define step validation with old UserValidator class--> <bean parent="define" id="validate"> <constructor-arg ref="userValidator"/> <constructor-arg value="validate"/> </bean> <!--define step makeTaller with old UserHandler class--> <bean parent="define" id="makeTaller"> <constructor-arg ref="userHandler"/> <constructor-arg value="makeTaller"/> </bean> <!--define step getRole with old validator class--> <bean parent="define" id="getUserRole"> <constructor-arg ref="userValidator"/> <constructor-arg value="getRole"/> </bean> <bean parent="define" id="setusername"> <constructor-arg value="setName"/> </bean> <bean id="userRoleEq2driver" parent="sequence"> <constructor-arg><list> <ref bean="getUserRole"/> <bean parent="eq2"> <constructor-arg><value type="java.lang.String">driver</value></constructor-arg> </bean> </list></constructor-arg> </bean> <!--define process one--> <bean id="process1" parent="choice"> <constructor-arg ref="userRoleEq2driver"/> <constructor-arg><map> <entry><key><value type="boolean">true</value></key><ref bean="demoActionOne"/></entry> <entry><key><value type="boolean">false</value></key><ref bean="demoActionTwo"/></entry> </map></constructor-arg> </bean> <bean id="p2" parent="sequence"> <constructor-arg><list> <ref bean="process1"/> <ref bean="makeTaller"/> <ref bean="demoActionOne"/> </list></constructor-arg> </bean> </beans> 核心类 Functor.java package com.gordon.functor; import java.util.HashMap; import java.util.Map; public abstract class Functor { public abstract Object apply(Object... args); public static Functor define(final String action){ return new Functor() { public Object apply(Object... args){ if(args==null)return null; if(args.length>1){ Object[] tail=new Object[args.length-1]; System.arraycopy(args,0,tail,0,tail.length); return run(args[args.length-1],action,tail); }else{ return run(args[0],action); } } }; } public static Functor define(final Object worker, final String action) { return new Functor() { public Object apply(Object... args) { return run(worker, action, args); } }; } public Functor and(final Functor... functors) { final Functor first = this; return new Functor() { public Object apply(Object... args) { Boolean result = (Boolean)first.apply(args); for (Functor f: functors) { result = result && (Boolean)f.apply(args); } return result; } }; } public Functor or(final Functor... functors) { final Functor first = this; return new Functor() { public Object apply(Object... args) { Boolean result = (Boolean)first.apply(args); for (Functor f: functors) { result = result || (Boolean)f.apply(args); } return result; } }; } public Functor sw(final Map<Object, Functor> switchMap) { final Functor f = this; return new Functor() { public Object apply(Object... args) { Object firstResult = f.apply(args); if (!switchMap.containsKey(firstResult)) return args; return switchMap.get(firstResult).apply(args); } }; } public Functor sw(Object... args) { if (args.length > 1 && args.length % 2 == 0) { Map<Object, Functor> sw = new HashMap<Object, Functor>(); for (int i = 0; i < args.length; i = i + 2) { sw.put(args[i], (Functor)args[i + 1]); } return this.sw(sw); } else throw new java.lang.IllegalArgumentException("incorrect number of arguments for Functor.sw , correct format should be (case,Functor,case,Functor...)"); } public Functor curry(final Object... pargs) { final Functor self = this; return new Functor() { public Object apply(Object... args) { Object[] arg = new Object[pargs.length + args.length]; System.arraycopy(pargs, 0, arg, 0, pargs.length); System.arraycopy(args, 0, arg, pargs.length, args.length); return self.apply(arg); } }; } public Functor then(final Functor... functors) { final Functor first = this; return new Functor() { public Object apply(Object... args) { Object result = first.apply(args); if (functors != null) for (Functor f: functors) { result = f.apply(result); } return result; } }; } public Functor to(final Object... args) { return this.curry(args); } public Functor than(final Object... args) { return this.curry(args); } protected static Object run(Object worker, String action, Object... arguments) { java.lang.reflect.Method mx = null; for (java.lang.reflect.Method m: worker.getClass().getMethods()) { if (m.getName().equals(action)) { mx = m; break; } } Object result = null; try { if (!mx.isVarArgs()) { result = mx.invoke(worker, arguments); } else { if (arguments.length == mx.getParameterTypes().length) { result = mx.invoke(worker, arguments); } else { Object[] args = new Object[mx.getParameterTypes().length]; for (int i = 0; i < args.length; i++) { if (i != args.length - 1) args[i] = arguments[i]; else { Object[] var = (Object[])java.lang.reflect.Array.newInstance(mx.getParameterTypes()[i].getComponentType(), arguments.length - i); System.arraycopy(arguments, i, var, 0, var.length); args[i] = var; } } result = mx.invoke(worker, args); } } } catch (Exception e) { e.printStackTrace(); } return result; } } 这个类是为了给spring写配置简单写用的 Combinator.java package com.gordon.functor; import java.util.List; import java.util.Map; public abstract class Combinator { public static Functor and(Functor... functors){ if(functors!=null) return head(functors).and(tail(functors)); else return null; } public static Functor and(List<Functor> functors){ if(functors!=null) return and(functors.toArray(new Functor[functors.size()])); else return null; } public static Functor or(Functor... functors){ if(functors!=null) return head(functors).or(tail(functors)); else return null; } public static Functor or(List<Functor> functors){ if(functors!=null) return or(functors.toArray(new Functor[functors.size()])); else return null; } public static Functor sw(Functor choice,Map<Object,Functor> switchMap){ return choice.sw(switchMap); } public static Functor sw(Functor choice,Object... args){ return choice.sw(args); } public static Functor curry(Functor self,Object... args){ return self.curry(args); } public static Functor sequence(List<Functor> functors){ return sequence(functors.toArray(new Functor[functors.size()])); } public static Functor sequence(Functor[] functors){ if(functors!=null) return head(functors).then(tail(functors)); else return null; } private static Functor head(Functor[] array){ if(array!=null&&array.length>0)return array[0]; else return null; } private static Functor[] tail(Functor[] array){ if(array.length<2) return null; Functor[] tail=new Functor[array.length-1]; System.arraycopy(array,1,tail,0,array.length-1); return tail; } public static Functor define(Object worker,String action){ return Functor.define(worker,action); } public static Functor define(String action){ return Functor.define(action); } } 一个基本的用来判断相等的Functor类 EqualFunctor.java package com.gordon.functor.functors; import com.gordon.functor.Functor; public class EqualFunctor extends Functor { public EqualFunctor() { } public Object apply(Object... args) { if(args.length<2) return null; return args[0].equals(args[1]); } } 测试用的其他类 User.java package com.gordon.functor.legacy; public class User{ private String name; private int age; private int height; public User(String name,int age,int height){ this.name=name; this.age=age; this.height=height; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public String toString(){ return "{name:"+this.name+",age:"+this.age+",height:"+this.height+"}"; } } UserHandler.java package com.gordon.functor.legacy; public class UserHandler { public UserHandler() { } public User makeTaller(User u){ if(u!=null)u.setHeight(u.getHeight()+10); return u; } public User demoActionOne(User u){ System.out.println("this is demo action one"); if(u!=null){ System.out.println("user="+u); } return u; } public User demoActionTwo(User u){ System.out.println("this is demo action two"); if(u!=null){ System.out.println("user="+u); } return u; } } UserValidator.java package com.gordon.functor.legacy; public class UserValidator{ public boolean validate(User u){ return (u.getName().equals("gordon")); } public String getRole(User u){ if(u.getName().equals("gordon"))return "developer"; if(u.getName().equals("jiacheng"))return "driver"; if(u.getName().equals("dylan"))return "dba"; return "staff"; } } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-02-29
能不能先告诉我这一大段到底是要干什么?
|
|
返回顶楼 | |
发表时间:2008-03-01
在java中实现functional programming的一些特性,并且可以和spring直接结合做流程引擎,具体请看刚补上的说明
ray_linn 写道 能不能先告诉我这一大段到底是要干什么?
|
|
返回顶楼 | |