Java中仿照C#代理

http://stackoverflow.com/questions/1184418/javas-equivalents-of-func-and-action
http://stackoverflow.com/questions/1340231/equivalent-of-c-sharp-anonymous-delegates-in-java
http://stackoverflow.com/questions/44912/java-delegates


问题:
In C#, you can define small pieces of code called delegates anonymously (even though they are nothing more than syntactic sugar). So, or example, I can do this:
------------------------------------------------------------------------------------
public string DoSomething(Func<string, string> someDelegate){
     // Do something involving someDelegate(string s)





DoSomething(delegate(string s){ return s += "asd"; });
DoSomething(delegate(string s){ return s.Reverse(); });
------------------------------------------------------------------------------------
Is it possible to pass code like this in Java? I'm using the processing framework, which has a quite old version of Java (it doesn't have generics).


答案:
Pre Java 8:
The closest Java has to delegates are single method interfaces. You could use an anonymous inner class.
------------------------------------------------------------------------------------
interface StringFunc {
   String func(String s);
}


void doSomething(StringFunc funk) {
   System.out.println(funk.func("whatever"));


}


doSomething(new StringFunc() {
      public String func(String s) {
           return s + "asd";


      }
});


doSomething(new StringFunc() {


      public String func(String s) {


           return new StringBuffer(s).reverse().toString();


      }


   });
------------------------------------------------------------------------------------
Java 8 and above:


Java 8 adds lambda expressions to the language.
------------------------------------------------------------------------------------
    doSomething((t) -> t + "asd");
    doSomething((t) -> new StringBuilder(t).reverse().toString());
------------------------------------------------------------------------------------


C#中拥有Action和Func,而Java到java 8才有类似的东西。
------------------------------------------------------------------------------------
Action<T> Delegate
Func<T, TResult> Delegate
------------------------------------------------------------------------------------


比如一个例子(http://msdn.microsoft.com/en-us/library/bb549151.aspx)
------------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;


static class Func
{
   static void Main(string[] args)
   {
      // Declare a Func variable and assign a lambda expression to the   
      // variable. The method takes a string and converts it to uppercase.
      Func<string, string> selector = str => str.ToUpper();


      // Create an array of strings. 
      string[] words = { "orange", "apple", "Article", "elephant" };
      // Query the array and select strings according to the selector method.
      IEnumerable<String> aWords = words.Select(selector);


      // Output the results to the console. 
      foreach (String word in aWords)
         Console.WriteLine(word);
   }
}      
/*
This code example produces the following output:


   ORANGE
   APPLE
   ARTICLE
   ELEPHANT
*/


------------------------------------------------------------------------------------
http://msdn.microsoft.com/en-us/library/018hxwa8.aspx


using System;
using System.Collections.Generic;


class Program
{
    static void Main()
    {
        List<String> names = new List<String>();
        names.Add("Bruce");
        names.Add("Alfred");
        names.Add("Tim");
        names.Add("Richard");


        // Display the contents of the list using the Print method.
        names.ForEach(Print);


        // The following demonstrates the anonymous method feature of C# 
        // to display the contents of the list to the console.
        names.ForEach(delegate(String name)
        {
            Console.WriteLine(name);
        });
    }


    private static void Print(string s)
    {
        Console.WriteLine(s);
    }
}
/* This code will produce output similar to the following:
 * Bruce
 * Alfred
 * Tim
 * Richard
 * Bruce
 * Alfred
 * Tim
 * Richard
 */
------------------------------------------------------------------------------------
但是可以模拟


------------------------------------------------------------------------------------
Callable interface is similar to Func.
Runnable interface is similar to Action
------------------------------------------------------------------------------------




下面是Steve Lewisd的一个实现
------------------------------------------------------------------------------------
http://onjava.com/pub/a/onjava/2003/05/21/delegates.html


package com.lordjoe.csharp;


import java.lang.reflect.*;
import java.util.List;
import java.util.ArrayList;


/**
 * com.lordjoe.csharp.Delegator Class representing a delegate tamplate - also a
 * factory treturning the real delegate object
 * 
 * @author Steve Lewis [email protected]
 */
public class Delegator {
  public static final Method[] EMPTY_METHOD_ARRAY = {};
  public static final Object[] EMPTY_OBJECT_ARRAY = {};
  public static final Delegator[] EMPTY_ARRAY = {};


  // convenience implementation
  public static final Delegator RUNNABLE_DELEGATE = new Delegator(
      Runnable.class);


  /**
   * Convenience method to make a runnable delegate
   * 
   * @param item
   *            non-null target object
   * @param methodName
   *            non-null name of a method of type void ()
   * @return non-null Runnable proxy
   */
  public static Runnable buildRunnable(Object item, String methodName) {
    return ((Runnable) RUNNABLE_DELEGATE.build(item, methodName));
  }


  /**
   * Convenience method to make a runnable delegate
   * 
   * @param item
   *            non-null target class
   * @param methodName
   *            non-null name of a method of type void ()
   * @return non-null Runnable proxy
   */
  public static Runnable buildRunnable(Class item, String methodName) {
    return ((Runnable) RUNNABLE_DELEGATE.build(item, methodName));
  }


  private final Class m_Interface; // may be null
  private final Class m_Return;
  private final Class[] m_Arguments;


  /**
   * 代理参数为params,返回值为retClass,没有接口的类型
   * @param params
   *            non-null array of arguments
   * @param retClass
   *            possibly null return class null says do not care
   */
  public Delegator(Class[] params, Class retClass) {
    m_Interface = null;
    m_Return = retClass;
    m_Arguments = params;
  }


  /**
   * 代理只有个方法的接口
   * @param TheInterface
   *            an non-null interface with EXACTLY one method
   */
  public Delegator(Class TheInterface) {
    m_Interface = TheInterface;
    Method met = findMethod(TheInterface);
    m_Return = met.getReturnType();
    m_Arguments = met.getParameterTypes();
  }


  /**
   * accessor for return class
   */
  public Class getReturn() {
    return m_Return;
  }


  /**
   * accessor for argument classes
   */
  public Class[] getArguments() {
    return m_Arguments;
  }


  public Class getInterface() {
    return m_Interface;
  }


  /**
   * 
   * @param target
   *            non-null class with a bindable static method
   * @param MethodName
   *            name of the static method
   * @return non-null IDelegate if getInterface() is non-null it will be a
   *         dynamic prozy implementing that interface
   */
  public IDelegate build(Class target, String MethodName) {
    Class myInterface = getInterface();
    DelegateProxy theDelegate = new DelegateProxy(null, target, MethodName,
        this);
    if (myInterface != null) {
      Class[] interfaces = { myInterface, IDelegate.class };
      IDelegate ret = (IDelegate) java.lang.reflect.Proxy
          .newProxyInstance(target.getClassLoader(), interfaces,
              theDelegate);
      return (ret);


    }
    return ((IDelegate) theDelegate);
  }


  /**
   * 
   * 通过一个对象和它的方法名创建一个代理对象
   * @param target
   *            non-null target with a bindable method
   * @param MethodName
   *            name of the method
   * @return non-null IDelegate if getInterface() is non-null it will be a
   *         dynamic prozy implementing that interface
   */
  public IDelegate build(Object target, String MethodName) {
    Class myInterface = getInterface();
    DelegateProxy theDelegate = new DelegateProxy(target,
        target.getClass(), MethodName, this);
    if (myInterface != null) { // build a dynamic proxy
      Class[] interfaces = { myInterface, IDelegate.class };
      IDelegate ret = (IDelegate) java.lang.reflect.Proxy
          .newProxyInstance(target.getClass().getClassLoader(),
              interfaces, theDelegate);
      return (ret);


    }
    if (!(theDelegate instanceof IDelegate))
      throw new ClassCastException();
    return ((IDelegate) theDelegate);
  }


  protected class DelegateProxy implements IDelegate, InvocationHandler {
    private final Method m_Method;
    private final Object m_Target;
    private final Delegator m_Template;


    /**
     * constructor supplying a Class passing in types not template
     * 
     * @param target
     *            possibly null target if null the method must be static
     * @param target
     *            non-null class implementing a suitable method
     * @param target
     *            non-null object implementing a suitable static method
     * @param MethodName
     *            nun-null name of a public static method in target
     * @param template
     *            non-null template with the required arguemts and return
     */
    protected DelegateProxy(Object target, Class targetClass,
        String MethodName, Delegator template) {
      m_Template = template;
      m_Target = target;
      Method meth = findSuitableMethod(targetClass, MethodName, template);
      m_Method = meth;
    }


    /**
     * convenience call to handle case of no arguments
     * 
     * @return whatever is returned
     */
    public Object invoke() throws IllegalArgumentException,
        DelegateInvokeException {
      return (invoke(EMPTY_OBJECT_ARRAY));
    }


    /**
     * convenience call to handle case of one argument
     * 
     * @param arg
     *            some argument
     * @return whatever is returned
     */
    public Object invoke(Object arg) throws IllegalArgumentException,
        DelegateInvokeException {
      Object[] args = { arg };
      return (invoke(args));
    }


    /**
     * convenience call to handle case of two argument
     * 
     * @param arg1
     *            some argument
     * @param arg2
     *            some argument
     * @return whatever is returned
     */
    public Object invoke(Object arg1, Object arg2)
        throws IllegalArgumentException, DelegateInvokeException {
      Object[] args = { arg1, arg2 };
      return (invoke(args));
    }


    /**
     * method required by InvocationHandler so we can build dynamic Proxys
     * 
     * @param proxy
     *            object for which we are a proxy (ignored)
     * @param method
     *            method to call (ignored)
     * @param args
     *            arguments to pass
     * @return whatever is returned primitive types are wrapped
     */
    public Object invoke(Object proxy, Method method, Object[] args) {
      return (invoke(args));
    }


    /**
     * basic call to method
     * 
     * @param args
     *            method arguments
     * @return whatever is returned
     */
    public Object invoke(Object[] args) throws IllegalArgumentException,
        DelegateInvokeException {
      // validateArgs(args);
      try {
        Object ret = getMethod().invoke(getTarget(), args);
        return (ret);
      } catch (IllegalAccessException ex1) {
        throw new IllegalStateException("Bad Delgate State"
            + ex1.getMessage()); // should not happen
      } catch (InvocationTargetException ex1) {
        throw new Delegator.DelegateInvokeException(ex1.getCause());
      }
    }


    /**
     * if uncommented in invoke this code will throw an IllegalArgument call
     * if arguments are of the wrong type
     */
    protected void validateArgs(Object[] args)
        throws IllegalArgumentException {
      Class[] MyArgs = getArguments();
      if (args.length != MyArgs.length)
        throw new IllegalArgumentException("Delegate required "
            + MyArgs.length + "arguments");
      for (int i = 0; i < args.length; i++) {
        if (!MyArgs[i].isInstance(args[i]))
          throw new IllegalArgumentException("Argument " + i
              + " must be of class " + MyArgs[i].getName());
      }
    }


    /**
     * accessor for the method
     */
    public Method getMethod() {
      return m_Method;
    }


    /**
     * accessor for the target
     */
    public Object getTarget() {
      return m_Target;
    }


  }// end class DelegateProxy


  /**
   * All problems become this type of exception As a runtime we do not impose
   * burdens on the calling code
   */
  public static class DelegateInvokeException extends RuntimeException {
    public DelegateInvokeException(Throwable cause) {
      super(cause);
    }
  }


  // ===================================================================
  // static utility methods in this section identify the
  // method in verious targets
  // ===================================================================


  /**
   * utility method to test suitability
   */
  protected static boolean isSuitableMethod(Method testMethod, Class[] args,
      Class retClass) {
    Class[] methodArgs = testMethod.getParameterTypes();
    for (int i = 0; i < methodArgs.length; i++) {
      Class arg = methodArgs[i];
      if (!arg.isAssignableFrom(args[i]))
        return (false);
    }
    // This is the only
    isValidReturn(testMethod, retClass);
    return (true);
  }


  /**
   * utility method to get candidate methods to search
   */
  protected static Method[] getCandidateMethods(Class targetClass,
      String MethodName, int nargs) {
    Method[] possibilities = targetClass.getMethods();
    List holder = new ArrayList();
    for (int i = 0; i < possibilities.length; i++) {
      Method possibility = possibilities[i];
      if (possibility.getName().equals(MethodName)
          && possibility.getParameterTypes().length == nargs
          && Modifier.isPublic(possibility.getModifiers()))
        holder.add(possibility);
    }
    return ((Method[]) holder.toArray(EMPTY_METHOD_ARRAY));
  }


  /**
   * utility method to test return
   */
  protected static boolean isValidReturn(Method test, Class retClass) {
    if (retClass == null)
      return (true); // we do not care
    if (test.getReturnType() == retClass)
      return (true);
    if (retClass.isAssignableFrom(test.getReturnType()))
      return (true);
    return (false);
  }


  /**
   * Utility method to locate a proper Method object
   * 从targetClass中找到合适的方法(f返回值和参数必须匹配)
   */
  protected static Method findSuitableMethod(Class targetClass,
      String MethodName, Delegator templ) {
    Class[] args = templ.getArguments();
    Class retClass = templ.getReturn();
    // perfect match
    try {
      Method ret = targetClass.getMethod(MethodName, args);
      if (!isValidReturn(ret, retClass))
        throw new IllegalArgumentException(
            "Requested method returns wrong type");
      if (!Modifier.isPublic(ret.getModifiers()))
        throw new IllegalArgumentException(
            "Requested method is not public");
      return (ret);
    } catch (Exception ex) {
    } // on to try2
    Method[] possibilities = getCandidateMethods(targetClass, MethodName,
        args.length);
    for (int i = 0; i < possibilities.length; i++) {
      Method possibility = possibilities[i];
      if (isSuitableMethod(possibility, args, retClass))
        return (possibility);
    }
    throw new IllegalArgumentException("No suitable method found");
  }


  /**
   * utility code to find the one suitable method in the passed in interface.
   * 找到接口中唯一的方法
   */
  protected static Method findMethod(Class TheInterface) {
    if (!TheInterface.isInterface())
      throw new IllegalArgumentException(
          "DelegateTemplate must be constructed with an interface");
    Method[] methods = TheInterface.getMethods();
    Method ret = null;
    for (int i = 0; i < methods.length; i++) {
      Method test = methods[i];
      if (Modifier.isAbstract(test.getModifiers())) {
        if (ret != null)
          throw new IllegalArgumentException(
              "DelegateTemplate must be constructed "
                  + " with an interface implementing only one method!");
        ret = test;
      }
    }
    if (ret == null)
      throw new IllegalArgumentException(
          "DelegateTemplate must be constructed "
              + " with an interface implementing exactly method!");
    return (ret);
  }


}
------------------------------------------------------------------------------------
package com.lordjoe.csharp;


/**
 * Interface implemnted by the object returned by Delegator.bind
 * Use this only when no suitable alternative interface is available
 * @author Steve Lewis
 * Date: May 9, 2002
 **/
public interface IDelegate {
    /**
     * Thin wrapper in invoke
     * @param args possibly null array or args - null says none
     * @return possibly null return - primitive types are wrapped
     */
     public Object invoke(Object[] args);
    /**
     * convenience call for 1 arg case
     * @param arg possibly null argument
     * @return possibly null return - primitive types are wrapped
     */
     public Object invoke(Object arg);


    /**
     * convenience call for 2 arg case
     * @param arg1 possibly null argument
     * @param arg2 possibly null argument
     * @return possibly null return - primitive types are wrapped
     */
     public Object invoke(Object arg1, Object arg2);


    /**
     * convenience call for no arg case
     * @return possibly null return - primitive types are wrapped
     */
     public Object invoke();
}


------------------------------------------------------------------------------------
package com.lordjoe.csharp;


import junit.framework.*;


/**
 * com.lordjoe.csharp.TestDelegate2
 * 
 * @author Steve Lewis [email protected]
 */
public class TestDelegate extends TestCase {
  public static final int ITER_COUNT = 10 * 1000 * 1000;


  /**
   * common interface - note No implementing class i.e. Class1 implements this
   */
  public static interface IStringDisplay {
    public void doDisplay(String s);
  }


  public TestDelegate(String name) {
    super(name);
  }


  /**
   * This section tests that DelegateTemplate fails when passed an unsuitable
   * interface
   */
  public static interface IBadStringDisplay {
    public void doDisplay(String s);


    public void doDisplay2(String s);
  }


  public static interface IBadStringDisplay2 {
  }


  public void testDelegateBuild() {
    try {
      //有两个方法,失败
      new Delegator(IBadStringDisplay.class);
      fail();
    } catch (IllegalArgumentException ex) {
      ex.printStackTrace();
      //DelegateTemplate must be constructed  with an interface implementing only one method!
    }
    try {
      //IBadStringDisplay2没有方法,失败
      new Delegator(IBadStringDisplay2.class);
      fail();
    } catch (IllegalArgumentException ex) {
      ex.printStackTrace();
      //DelegateTemplate must be constructed  with an interface implementing exactly method!
    }
  }


  /**
   * code to test calls to delegate
   */
  public void testDelegate() throws Exception {
    Delegator myDelegate = new Delegator(IStringDisplay.class);
    Class1 obj1 = new Class1();
    Class2 obj2 = new Class2();
    IStringDisplay[] items = new IStringDisplay[3];
    items[0] = (IStringDisplay) myDelegate.build(obj1, "show");
    items[1] = (IStringDisplay) myDelegate.build(obj2, "display");
    items[2] = (IStringDisplay) myDelegate.build(Class3.class,
        "staticDisplay");


    for (int i = 0; i < items.length; i++) {
      IStringDisplay item = items[i];
      item.doDisplay("test");
    }
    
    /**
     * ==>doDisplay调用InvocationHandler(DelegateProxy)的invoke方法
     * ==>在invoke方法中的调用display、show、staticDisplay等方法,并且将doDisplay才参数传递进去
     */
    // timingTest(items,obj1,obj2,ITER_COUNT);
  }


  /**
   * code to test calls to delegate
   */
  public void testDelegateInvoke() throws Exception {
    Class[] params = { String.class };
    Delegator myDelegate = new Delegator(params, Void.TYPE);
    Class1 obj1 = new Class1();
    Class2 obj2 = new Class2();
    IDelegate[] items = new IDelegate[3];
    items[0] = myDelegate.build(obj1, "show");
    items[1] = myDelegate.build(obj2, "display");
    items[2] = myDelegate.build(Class3.class, "staticDisplay");


    for (int i = 0; i < items.length; i++) {
      IDelegate item = items[i];
      item.invoke("test");
    }
    
    //静态代理
  }


  /**
   * Test of timing - note set iteration large i.e. 1000000 for resaonbale
   * results
   */
  public void timingTest(IStringDisplay[] items, Class1 obj1, Class2 obj2,
      int iterations) {
    // Warm up hotspot
    for (int k = 0; k < 100; k++) {
      for (int i = 0; i < items.length; i++) {
        IStringDisplay item = items[i];
        item.doDisplay("test");
      }
      obj1.show("test");
      obj2.display("test");
      Class3.staticDisplay("test");
    }
    long start = System.currentTimeMillis();
    for (int j = 0; j < iterations; j++) {
      for (int i = 0; i < items.length; i++) {
        IStringDisplay item = items[i];
        item.doDisplay("test");
      }
    }
    long end = System.currentTimeMillis();
    double delegateTime = (end - start) / 1000;
    double perIteration = 1000 * 1000 * delegateTime / iterations;


    start = System.currentTimeMillis();
    for (int j = 0; j < iterations; j++) {
      obj1.show("test");
      obj2.display("test");
      Class3.staticDisplay("test");
    }
    end = System.currentTimeMillis();
    double directTime = (end - start) / 1000;
    double perCallIteration = 1000 * 1000 * directTime / iterations;


    System.out.println("Ran " + iterations + " iterations ");
    System.out.println("Delegate Test took " + delegateTime + "sec");
    System.out.println("per iteration " + perIteration + "microsec");
    System.out.println("Direct Calls took " + directTime + "sec");
    System.out.println("per iteration " + perCallIteration + "microsec");


  }


  public static Test suite() {
    return new TestSuite(TestDelegate.class);
  }


  public static void main(String[] args) {
    String[] RealArgs = { "com.lordjoe.csharp.TestDelegate3" };
    // junit.swingui.TestRunner.main(RealArgs);
    junit.textui.TestRunner.main(RealArgs);
  }


}


/**
 * some classes we need to call method body might printout fir vicibility or
 * increment a variable for timing test (to prevent optimizing out)
 */
class Class1 {
  int count;


  public void show(String s) {
    count++; // System.out.println(s);
    System.out.println("Class3 show " +s+" "+count);
  }
}


class Class2 {
  int count;


  public void display(String s) {
    count++;// System.out.println(s);
    System.out.println("Class2 display " +s+" "+count);
  }
}


/**
 * here the methos is static
 */
class Class3 { // allows static method as well
  static int count;


  public static void staticDisplay(String s) {
    count++; // System.out.println(s);
    System.out.println("Class3 staticDisplay " +s+" "+count);
  }
}


------------------------------------------------------------------------------------

你可能感兴趣的:(Java中仿照C#代理)