一些说明,仿佛没有说明的代码基本都没有人会看
[color=red]
以下代码是为了用200行以内的java代码实现一些functional programming的特性,并且可以直接用spring定义任意程序流程.
[/color]
User类是一个pojo
UserHandler和UserValidator是包含一些业务逻辑的类,包含了一些业务方法,
包括一下方法
UserValidator.java
UserHandler.java
现在可以直接通过对这些已经有的功能组合就能有新的功能,比如
这样的代码
可以这样写
这里的newProcess就是一个新的程序流程(或者说片断),
也可以使用标准的spring xml定义作为程序流程定制
比如
仔细考虑一下,用fp做个简单的流程拼装器应该会比较简单。
把上次的代码稍微修改一下,再配上spring就马上可以订制流程咯。
测试代码
Test.java
流程定义文件
flow.xml
核心类
Functor.java
这个类是为了给spring写配置简单写用的
Combinator.java
一个基本的用来判断相等的Functor类
EqualFunctor.java
测试用的其他类
User.java
UserHandler.java
UserValidator.java
[color=red]
以下代码是为了用200行以内的java代码实现一些functional programming的特性,并且可以直接用spring定义任意程序流程.
[/color]
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";
}
}