Java运行时类型解析的最佳实践

我正在尝试定义一个类(或一组实现相同接口的类),它将表现为松散类型的对象(如
JavaScript).它们可以根据底层类型保存任何类型的数据和操作.

我有三种不同的工作方式,但似乎都不理想.这些测试版本只允许字符串和整数,唯一的操作是添加.添加整数会产生整数值的总和,添加字符串连接字符串并向字符串添加整数会将整数转换为字符串并将其与字符串连接.最终版本将有更多类型(双打,数组,类似JavaScript的对象,可以动态添加新属性)和更多操作.

方式1:

public interface DynObject1 {
  @Override public String toString();
  public DynObject1 add(DynObject1 d);
  public DynObject1 addTo(DynInteger1 d);
  public DynObject1 addTo(DynString1 d);
}


public class DynInteger1 implements DynObject1 {
  private int value;

  public DynInteger1(int v) {
    value = v;
  }

  @Override
  public String toString() {
    return Integer.toString(value);
  }

  public DynObject1 add(DynObject1 d) {
    return d.addTo(this);
  }

  public DynObject1 addTo(DynInteger1 d) {
    return new DynInteger1(d.value + value);
  }

  public DynObject1 addTo(DynString1 d)
  {
    return new DynString1(d.toString()+Integer.toString(value));
  }
}

……和DynString1类似

方式2:
    公共接口DynObject2 {
      @Override public String toString();
      public DynObject2 add(DynObject2 d);
    }

public class DynInteger2 implements DynObject2 {
  private int value;

  public DynInteger2(int v) {
    value = v;
  }

  @Override
  public String toString() {
    return Integer.toString(value);
  }

  public DynObject2 add(DynObject2 d) {
    Class c = d.getClass();

    if(c==DynInteger2.class)
    {
      return new DynInteger2(value + ((DynInteger2)d).value);
    }
    else
    {
      return new DynString2(toString() + d.toString());
    }
  }
}

……和DynString2类似

方式3:

public class DynObject3 {

  private enum ObjectType {
    Integer,
    String
  };

  Object value;
  ObjectType type;

  public DynObject3(Integer v) {
    value = v;
    type = ObjectType.Integer;
  }

  public DynObject3(String v) {
    value = v;
    type = ObjectType.String;
  }

  @Override
  public String toString() {
    return value.toString();
  }

  public DynObject3 add(DynObject3 d)
  {
    if(type==ObjectType.Integer && d.type==ObjectType.Integer)
    {
      return new DynObject3(Integer.valueOf(((Integer)value).intValue()+((Integer)value).intValue()));
    }
    else
    {
      return new DynObject3(value.toString()+d.value.toString());
    }
  }
}

使用if-else逻辑我可以使用value.getClass()== Integer.class而不是存储类型但是有更多类型我会改变它以使用switch语句而Java不允许switch使用Classes.

无论如何……我的问题是什么是最好的方式来解决这个问题?

最佳答案 您要做的事情称为
double dispatch.您希望调用的方法既依赖于它所调用的对象的运行时类型,又依赖于其参数的运行时类型.

Java和其他C衍生产品仅支持单一调度,这就是为什么你需要像选项1中使用的visitor pattern这样的kludge.这是实现它的常用方法.我更喜欢这种方法,因为它不使用反射.此外,它允许您将每个案例保留在自己的方法中,而无需使用大的“交换机”方法来执行调度.

点赞