方法接受两种不同类型作为参数(Method accepting two different type

2019-06-24 21:20发布

我写的是应该接受作为参数两种类型之一的对象不共享比其他对象的父类的方法。 例如,类型是梦想和大蒜。 你既可以做dreams.crush()garlic.crush() 我想有一个方法utterlyDestroy(parameter) ,这将接受作为它的参数都梦想和大蒜。

utterlyDestroy(parameter) {
    parameter.crush()
}

无论大蒜和梦想是一些库的一部分,所以让他们实现一个接口ICrushable(这样我就可以写utterlyDestroy(ICrushable parameter) )是不是一种选择。

我的方法体相当长,所以超载这将意味着重复的代码。 丑陋。 我相信我可以使用反射,并做一些类的黑客。 丑陋。

我尝试使用仿制药,但显然我不能喜欢写东西

utterlyDestroy(<T instanceof Dreams || T instanceof Garlic> parameter)

是否可以强制转换大蒜梦?

utterlyDestroy(Object parameter) {
    ((Dreams)parameter).crush()
}

这仍然是丑陋的,但。 我有哪些其他的选择,什么是处理这种情况的最佳方法?

Answer 1:

这个怎么样:

interface ICrushable {
    void crush();
}

utterlyDestroy(ICrushable parameter) {
    // Very long crushing process goes here
    parameter.crush()
}

utterlyDestroy(Dreams parameter) {
    utterlyDestroy(new ICrushable() { crush() {parameter.crush();});
}

utterlyDestroy(Garlic parameter) {
    utterlyDestroy(new ICrushable() { crush() {parameter.crush();});
}

新的发展应该实现ICrushable接口,但对于现有的类,参数被包装在一个ICrushable并传递给utterlyDestroy(ICrushable)做所有的工作。



Answer 2:

如何这么简单的东西吗?

utterlyDestroy(Object parameter) {    
    if(parameter instanceOf Dreams){  
        Dream dream = (Dreams)parameter;  
        dream.crush();
        //Here you can use a Dream 
    }  
    else if(parameter instanceOf Garlic){  
       Garlic garlic = (Garlic)parameter;   
        //Here you can use a Garlic  
       garlic.crush();  
   }
} 

如果utterlyDestroy太复杂,大的,你只是要拨打的crush那么这你想要做什么



Answer 3:

您可以用Java实现一个Haskell式的任一类; 是这样的:

class Either<L,R>
{
    private Object value;

    public static enum Side {LEFT, RIGHT}

    public Either(L left)  {value = left;}
    public Either(R right) {value = right;}

    public Side getSide() {return value instanceof L ? Side.LEFT : Side.RIGHT;}

    // Both return null if the correct side isn't contained.
    public L getLeft() {return value instanceof L ? (L) value : null;}
    public R getRight() {return value instanceof R ? (R) value : null;}
}

然后,你让那个方法取类型的东西Either<Dreams, Garlic>



Answer 4:

只需使用方法重载。

public void utterlyDestroy(Dreams parameter) {
    parameter.crush();
}

public void utterlyDestroy(Garlic parameter) {
    parameter.crush();
}

如果你想支持比这两类以同样的方式更多,你可以为它们定义的所有共同的界面和使用泛型。



Answer 5:

你可以使用一个接口, 适应你的类型吧。

接口:

public interface Crushable {
  public void crush();
}

例如调用:

public class Crusher {
  public static void crush(Crushable crushable) {
    crushable.crush();
  }
}

实施例适配器工厂方法:

public final class Dreams {
  public static Crushable asCrushable(final Dream dream) {
    class DreamCrusher implements Crushable {
      @Override
      public void crush() {
        dream.crush();
      }
    }
    return new DreamCrusher();
  }

  private Dreams() {}
}

消费者的代码如下所示:

  Dream dream = new Dream();
  Crushable crushable = Dreams.asCrushable(dream);
  Crusher.crush(crushable);

如果你有很多种类,以适应,你可以考虑反射。 下面是使用的(未优化)适配器工厂代理类型:

public final class Crushables {
  private static final Class<?>[] INTERFACES = { Crushable.class };

  public static Crushable adapt(final Object crushable) {
    class Handler implements InvocationHandler {
      @Override
      public Object invoke(Object proxy, Method method, Object[] args)
          throws Throwable {
        return crushable.getClass()
            .getMethod(method.getName(), method.getParameterTypes())
            .invoke(crushable, args);
      }
    }

    ClassLoader loader = Thread.currentThread()
        .getContextClassLoader();
    return (Crushable) Proxy.newProxyInstance(loader, INTERFACES, new Handler());
  }

  private Crushables() {}
}

对API的消费者,这不是丑:

  Dream dream = new Dream();
  Crushable crushable = Crushables.adapt(dream);
  Crusher.crush(crushable);

然而,正如以往的反射,你牺牲编译时类型检查。



Answer 6:

如果你要善待他们在​​项目的许多地方以同样的方式,我建议将它们包装在一个类中,类似的适配器。



Answer 7:

创建接口可压碎好像去最彻底的方法。 是子类型大蒜或梦想的一个选项,并增加你的界面亚型?

除非,你可以把公共代码的私有方法,并有utterlyDestroy的两个版本做他们必须做个别对象调用什么共同的代码之前。 如果你的方法体长,可能需要把它分解成私有方法反正。 我猜你已经想到了这一点,不过,因为它甚至比添加接口较为明显的解决方案。

您可以将参数作为对象,然后将它转换。 这是您的反射是什么意思? 即

public void utterlyCrush(Object crushable) {
    if (crushable instanceOf Dream) {
         ...
    }
    if (curshable instanceOf Garlic) {
         ...
    }

但是,从铸造到大蒜梦是不是因为一个是不是其他的子类型的选项。



Answer 8:

由于我使用的是:

void fooFunction(Object o){
Type1 foo=null;
if(o instanceof Type1) foo=(Type1)o;
if(o instanceof Type2) foo=((Type2)o).toType1();
// code
}

但是,这只是工作,如果2型可转换为类型1



文章来源: Method accepting two different types as parameter