Java双重调度和通用性

时间:2013-11-08 19:27:27

标签: java generics double-dispatch

我需要扩展一种广泛使用双重调度模式的算法。

该算法操纵一些不同的数据类(很多类),每个类都需要相同的扩展名。

我不想修改现有的数据类(用于限制序列化问题),也不想修改算法类(用于限制回归)。所以我设计了一个使用新类的解决方案。

我想使用类似下面的示例,但java拒绝识别我的类型。

import Main.Data1;
import Main.ExtendedData;

public class Main
{
  static interface OperatorDispatcher
  {
    void dispatchDoSomething( OperatorDispatch operator );
  }

  static class Data1 implements OperatorDispatcher
  {
    @Override
    public void dispatchDoSomething( OperatorDispatch operator )
    {
      operator.doSomething( this );
    }    
  }

  static class Data2 implements OperatorDispatcher
  {
    @Override
    public void dispatchDoSomething( OperatorDispatch operator )
    {  
      operator.doSomething( this );
    }    
  }

  static interface OperatorDispatch
  {
    void doSomething( Data1 data );
    void doSomething( Data2 data );
  }

  static class MyOperator implements OperatorDispatch
  {
    public void doSomething( Data1 data1 )
    {
      System.out.println( "doSomething with Data1 : " + data1 );
    }

    public void doSomething( Data2 data2 )
    {
      System.out.println( "doSomething with Data2 : " + data2 );
    }
  }

  static interface ExtendedOperatorDispatch
  {
    void doSomething( Data1 data, Object extension );
    void doSomething( Data2 data, Object extension );
  }

  static class MyExtendedOperator implements ExtendedOperatorDispatch
  {
    public void doSomething( Data1 data1, Object extension )
    {
      System.out.println( "doSomething with Data1 : " + data1 + " and " + extension );
    }

    public void doSomething( Data2 data2, Object extension )
    {
      System.out.println( "doSomething with Data2 : " + data2 + " and " + extension );
    }
  }

  static interface ExtendedOperatorDispatcher extends OperatorDispatcher
  {        
    void dispatchDoSomething( ExtendedOperatorDispatch operator );
  }

  /*
   * I don't want to specialize this class for each data type.
   */
  static class ExtendedData< T > implements ExtendedOperatorDispatcher
  {
    T _data;
    Object _extension;

    public ExtendedData( T data, Object extension )
    {
      _data = data;
      _extension = extension;
    }

    @Override
    public void dispatchDoSomething( OperatorDispatch operator )
    {  
      /*
       * ERROR : The method doSomething(Main.Data1) in the type Main.OperatorDispatch is not applicable for the arguments (T)
       */
      operator.doSomething( _data );
    }

    @Override
    public void dispatchDoSomething( ExtendedOperatorDispatch operator )
    {  
      /*
       * ERROR : The method doSomething(Main.Data1, Object) in the type Main.ExtendedOperatorDispatch is not applicable for the arguments (T, Object)
       */
      operator.doSomething( _data, _extension );
    }    
  }

  public static void main( String[] args )
  {
    MyOperator operator = new MyOperator();

    Data1 data10 = new Data1();
    data10.dispatchDoSomething( operator );

    Data1 data11 = new Data1();
    data11.dispatchDoSomething( operator );

    Data2 data20 = new Data2();
    data20.dispatchDoSomething( operator );

    MyExtendedOperator extendedOperator = new MyExtendedOperator();

    ExtendedData< Data1 > extendedData10 = new ExtendedData< Data1 >( data10, "EXTENSION" );
    extendedData10.dispatchDoSomething( operator );
    extendedData10.dispatchDoSomething( extendedOperator );

    ExtendedData< Data2 > extendedData20 = new ExtendedData< Data2 >( data20, "EXTENSION" );
    extendedData20.dispatchDoSomething( operator );
    extendedData20.dispatchDoSomething( extendedOperator );    
  }  
}

你知道如何解决它或者你想到另一个解决方案,随时回答。

感谢的

1 个答案:

答案 0 :(得分:0)

这可以解决问题,但可能有一个更简单的解决方案。 对于调度,如果性能不是至关重要的话,可以使用反射。 请注意,必须只有一种兼容的方法才能工作。

class ExtendedData<T> implements ExtendedOperatorDispatcher {
    T _data;
    Object _extension;
    private Class<? extends Object> _dataClass;
    private Class<? extends Object> _extensionClass;

    public ExtendedData(T data, Object extension) {
        _data = data;
        _extension = extension;
        _dataClass = (_data == null ? Object.class : _data.getClass());
        _extensionClass = (_extension == null ? Object.class : _extension
                .getClass());
    }

    @Override
    public void dispatchDoSomething(OperatorDispatch operator) {
        try {
            Method foundMethod = null;
            for (Method method : operator.getClass().getMethods()) {
                Class<?>[] params = method.getParameterTypes();
                if ("doSomething".equals(method.getName())
                        && params.length == 1)
                    if (params[0].isAssignableFrom(_dataClass)) {
                        if (foundMethod == null)
                            foundMethod = method;
                        else
                            throw new IllegalArgumentException(
                                    "Multiple method can be called");
                    }
            }
            foundMethod.invoke(operator, _data);
        } catch (SecurityException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void dispatchDoSomething(ExtendedOperatorDispatch operator) {
        try {
            Method foundMethod = null;
            for (Method method : operator.getClass().getMethods()) {
                Class<?>[] params = method.getParameterTypes();
                if ("doSomething".equals(method.getName())
                        && params.length == 2)
                    if (params[0].isAssignableFrom(_dataClass) && params[1].isAssignableFrom(_extensionClass)) {
                        if (foundMethod == null)
                            foundMethod = method;
                        else
                            throw new IllegalArgumentException(
                                    "Multiple method can be called");
                    }
            }
            foundMethod.invoke(operator, _data, _extension);
        } catch (SecurityException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}