论坛首页 Java企业应用论坛

在java中小试FP(二)

浏览 1919 次
精华帖 (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";
    }
}
   发表时间:2008-02-29  
能不能先告诉我这一大段到底是要干什么?
0 请登录后投票
   发表时间:2008-03-01  
在java中实现functional programming的一些特性,并且可以和spring直接结合做流程引擎,具体请看刚补上的说明
ray_linn 写道
能不能先告诉我这一大段到底是要干什么?

0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics