Java泛型-接受不同泛型接口的方法

Java泛型-接受不同泛型接口的方法,java,generics,design-patterns,Java,Generics,Design Patterns,假设我有这个代码: IOperation<?> parameter1 = null; ITotallyDifferentOperation<?> parameter2 = null; switch (OPERATION_TYPE) { case TYPE_1: parameter1 = new MyOperation<Type1>(); parameter2 = new MyTotallyDifferentOperation<Typ

假设我有这个代码:

IOperation<?> parameter1 = null;
ITotallyDifferentOperation<?> parameter2 = null;

switch (OPERATION_TYPE) {
  case TYPE_1:
    parameter1 = new MyOperation<Type1>();
    parameter2 = new MyTotallyDifferentOperation<Type1>();
    break;
  case TYPE_2:
    parameter1 = new MyOperation<Type2>();
    parameter2 = new MyTotallyDifferentOperation<Type2>();
    break;

...

switch (DB_OPERATION_TYPE) {
  case DB_TYPE_1:
    myMethod(parameter1, parameter2);
    break;
  case DB_TYPE_2:
    myOtherMethod(parameter1, parameter2);
    break;

...
TotalyDifferentionOperation.getList()
返回一个
列表
,该列表在
操作接受的
列表
类型上相等

此代码显然无法编译。
是否有其他模式可以获得相同的结果,或者此代码可以更正

应要求,我发布了更多的方法。不幸的是,我不能透露更多,这是一个模型。
我需要这种模式来避免代码重复。

阅读。您可以向方法添加类型参数,以确保操作和TotalyDifferention操作适用于同一类型:

<T> void myMethod(IOperation<T> operation,
                  ITotallyDifferentOperation<T> totallyDifferentOperation)
{
    operation.processList(totallyDifferentOperation.getList());
}

通过将这两个操作包装到类型化参数对象中,可以确保它们属于相同的类型。这当然意味着您的dbOperations需要接受param对象,而不是两个单独的参数。

在这里没有现成的设计模式可以帮助您


您的问题在于您对这些变量的声明:

IOperation<?> parameter1 = null;
ITotallyDifferentOperation<?> parameter2 = null;
IOOperation参数1=null;
ItotallyDifferentitoOperation参数2=null;
通过使用通配符,可以有效地告诉编译器“我不关心类型”。那不是真的。最终你会在乎你的类型

从根本上说,您的方法试图做的太多,这就是导致您出现问题的原因。将其分解为多种方法,会变得更简单:

switch (OPERATION_TYPE) {
   case TYPE_1:
      typeOne();
   case TYPE_2:
      typeTwo();
}

private void typeOne()
{
    IOperation<Type1> parameter1 = new MyOperation<>();
    ITotallyDifferentOperation<Type1> parameter2 = new MyTotallyDifferentOperation<>();

    doTheChecks(parameter1, parameter2);
    databaseStuff(parameter1, parameter2);
}

private void typeTwo() /*identical to above, except the types*/
{
    IOperation<Type2> parameter1 = new MyOperation<>();
    ITotallyDifferentOperation<Type2> parameter2 = new MyTotallyDifferentOperation<>();

    doTheChecks(parameter1, parameter2);
    databaseStuff(parameter1, parameter2);
}

<T> void doTheChecks(IOperation<T> param1, ITotallyDifferentOperation<T> param2)
{
    ...
}

<T> void databaseStuff(IOperation<T> param1, ITotallyDifferentOperation<T> param2)
{
    switch (DB_OPERATION_TYPE) {
        case DB_TYPE_1:
            myMethod(param1, param2);
            break;
        case DB_TYPE_2:
            myOtherMethod(param1, param2);
            break;
    }
}
开关(操作类型){
案例类型_1:
typeOne();
案例类型2:
类型二();
}
私有void typeOne()
{
IOOperation参数1=新的MyOperation();
ItotallyDifferention操作参数2=新MyTotalyDifferention操作();
Dothecks(参数1、参数2);
数据库材料(参数1、参数2);
}
私有void typeTwo()/*与上述相同,但类型不同*/
{
IOOperation参数1=新的MyOperation();
ItotallyDifferention操作参数2=新MyTotalyDifferention操作();
Dothecks(参数1、参数2);
数据库材料(参数1、参数2);
}
检查无效(IOOperation参数1,ITotallyDifferention操作参数2)
{
...
}
void databaseStuff(IOOperation参数1、ITotallyDifferention操作参数2)
{
开关(DB\U操作\U型){
案例数据库类型1:
myMethod(参数1,参数2);
打破
案例数据库类型2:
肌热法(param1,param2);
打破
}
}

详细阐述迈克尔的回答这就是我想到的。 看起来差不多不错;)

开关(操作){
案例类型_1:
processDbOperation(
数据库操作,
新的MyOperation(),
新MyTotalyDifferention());
打破
案例类型2:
processDbOperation(
数据库操作,
新的MyOperation(),
新MyTotalyDifferention());
打破
...
void processDbOperation(最终DbOperation DbOperation、最终IOOperation、最终ITotallyDifferention操作Total Differention操作){
开关(DBO操作){
案例数据库类型1:
myMethod(参数1、参数2);
打破
案例数据库类型2:
肌热法(参数1,参数2);
打破
}
...

我假设您的操作类和接口如下所示:

interface IOperation<T> {
    public List<T> processList(List<T> list);
    public List<T> getList();
}

interface ITotallyDifferentOperation<T> {
    public List<T> processList(List<T> list);
    public List<T> getList();
}

class MyOperation<T> implements IOperation<T> {
    public List<T> processList(List<T> list) {return null;}
    public List<T> getList() {return null;}
}

class MyTotallyDifferentOperation<T> implements ITotallyDifferentOperation<T> {
    public List<T> processList(List<T> list) {return null;}
    public List<T> getList() {return null;}
}
void myMethod(final IOperation<?> parameter1,
final ITotallyDifferentOperation<?> parameter2) {
    // COMPILE ERROR: processList() is not applicable for the arguments
    parameter1.processList(parameter2.getList());
}
要调用此方法,请执行以下操作:

final int DB_OPERATION_TYPE = 1;
someMethod(String.class, DB_OPERATION_TYPE);
// OR
someMethod(DB_OPERATION_TYPE, new MyOperation<String>(), MyTotallyDifferentOperation<String>());
final int DB_OPERATION_TYPE=1;
someMethod(String.class,DB\u操作类型);
//或
someMethod(DB_OPERATION_TYPE,new MyOperation(),myTotalyDifferention());
至于将方法调用引入交换机并完全放弃参数:Op澄清了这不是一个选项


Op只是在我的答案发布后才向您澄清了这一点。我现在已将其从我的答案中编辑出来。

如何额外传递描述类型参数的类对象?然后基本上是非擦除类型。

这实际上是我尝试的第一件事。但是,由于初始对象是使用通配符,这显示了编译错误。特别是在方法调用行中。是否存在在案例中不立即调用该方法的原因?这样,您就不需要声明通配符变量:
case TYPE_1:myMethod(new MyOperation(),new mytotalydifferentitooperation())
在调用方法之前,我还有其他条件需要评估。不幸的是,我无法在方法调用中直接初始化类型。您能将这些检查添加到您的问题中吗?是的,我认为最终两个答案背后的想法是相似的:将两个参数封装在一个对象/方法中,以确保它们都是相同的类型。Ei另外,希望它能对未来有所帮助。你是对的。我试图做的目标是消除重复Dothecks()和databaseStuff()的需要在每种类型上。不通配符参数将不会编译,因为
T
无法解决。这就是全部问题:您不知道它是哪种类型。至于将方法调用引入交换机并完全丢弃参数:Op澄清了这不是一个选项。现在,您已经为
某些类型添加了方法签名方法
我了解
T
的来源。很抱歉,我之前没有看到它。仍然存在一个问题,即您无法指定
MyOp
MyTot的类型…
。在将它们分配给变量时使用
Type1
String
仍然会导致编译错误。我猜它们必须是毕竟是作为参数传入的。@MalteHartwig是的,我可能从一开始就应该包括
someMethod
,我只是不知道上下文Op正在调用他的代码。哎呀,
someMethod
是不可重用的,再次编辑。你是对的,包括参数将是解决这个问题的一个好方法,我还包括了pass选项在一个类对象中使用这个类型。谢谢你捕捉到这个。但是你仍然需要使用这个类型。你可以
switch (operation) {
  case TYPE_1:
    processDbOperation(
      dbOperation, 
      new MyOperation<Type1>(), 
      new MyTotallyDifferentOperation<Type1>());
    break;
  case TYPE_2:
    processDbOperation(
      dbOperation, 
      new MyOperation<Type2>(),
      new MyTotallyDifferentOperation<Type2>());
    break;

...

<T> void processDbOperation(final DbOperation dbOperation, final IOperation<T> operation, final ITotallyDifferentOperation<T> totallyDifferentOperation) {
  switch (dbOperation) {
    case DB_TYPE_1:
      myMethod(parameter1, parameter2);
      break;
    case DB_TYPE_2:
      myOtherMethod(parameter1, parameter2);
      break;
}

...
interface IOperation<T> {
    public List<T> processList(List<T> list);
    public List<T> getList();
}

interface ITotallyDifferentOperation<T> {
    public List<T> processList(List<T> list);
    public List<T> getList();
}

class MyOperation<T> implements IOperation<T> {
    public List<T> processList(List<T> list) {return null;}
    public List<T> getList() {return null;}
}

class MyTotallyDifferentOperation<T> implements ITotallyDifferentOperation<T> {
    public List<T> processList(List<T> list) {return null;}
    public List<T> getList() {return null;}
}
void myMethod(final IOperation<?> parameter1,
final ITotallyDifferentOperation<?> parameter2) {
    // COMPILE ERROR: processList() is not applicable for the arguments
    parameter1.processList(parameter2.getList());
}
Operation<T> parameter1 = null;
ITotallyDifferentOperation<T> parameter2 = null;
void <T> myMethod(
final IOperation<T> operation,
final ITotallyDifferentOperation<T> totallyDifferentOperation) {
    operation.processList(totallyDifferentOperation.getList());
}
interface IOperation<T> {
    public List<T> processList(List<?> list);
    public List<T> getList();
}

interface ITotallyDifferentOperation<T> {
    public List<T> processList(List<?> list);
    public List<T> getList();
}
// remove wildcards, use a generic method, rather than deciding Type in a switch statment.
<T> void someMethod(final Class<T> klass, final int DB_OPERATION_TYPE) {
    IOperation<T> parameter1 = new MyOperation<T>();
    ITotallyDifferentOperation<T> parameter2 = new MyTotallyDifferentOperation<T>();

// ... OR ...

<T> void someMethod(final int DB_OPERATION_TYPE, IOperation<T> parameter1,
    ITotallyDifferentOperation<T> parameter2) {

    // ... Other conditions to evaluate before calling the myMethod ...

    switch(DB_OPERATION_TYPE) {
        case 1:
            myMethod(parameter1, parameter2);
            break;
        case 2:
            myOtherMethod(parameter1, parameter2);
            break;
    }
}

<T> void myMethod(final IOperation<T> operation, final ITotallyDifferentOperation<T> totallyDifferentOperation) {
    operation.processList(totallyDifferentOperation.getList());
}

<T> void myOtherMethod(final IOperation<T> operation, final ITotallyDifferentOperation<T> totallyDifferentOperation) {
    // something... ?
} 
final int DB_OPERATION_TYPE = 1;
someMethod(String.class, DB_OPERATION_TYPE);
// OR
someMethod(DB_OPERATION_TYPE, new MyOperation<String>(), MyTotallyDifferentOperation<String>());