[英]Java Generics - method which accept different generic interfaces
说我有这个代码:
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;
...
接受MyOperation
和MyTotallyDifferentOperation
实现的两个interfaces
的方法:
void myMethod(final IOperation<?> operation, final ITotallyDifferentOperation<?> totallyDifferentOperation) {
operation.processList(totallyDifferentOperation.getList());
}
totallyDifferentOperation.getList()
返回一个List<T>
,它与operation.processList()
接受的List<T>
类型相同。
这段代码显然无法编译。
是否有其他模式可以获得相同的结果,或者可以更正此代码?
根据要求,我发布了更多的方法。 不幸的是,我不能再透露,这是一个模型。
我需要这种模式以避免重复代码。
没有既定的设计模式可以帮助您。
您的问题在于您声明这些变量:
IOperation<?> parameter1 = null;
ITotallyDifferentOperation<?> parameter2 = 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;
}
}
阅读关于泛型方法参数的Java教程 。 您可以向方法添加类型参数,以确保操作和fullyDifferentOperation适用于相同的类型:
<T> void myMethod(IOperation<T> operation,
ITotallyDifferentOperation<T> totallyDifferentOperation)
{
operation.processList(totallyDifferentOperation.getList());
}
这样您就可以确保两个参数的输入方式与调用者相同:
// compiles
myMethod(new MyOperation<Type1>(), new MyTotallyDifferentOperation<Type1>())
// does not compile
myMethod(new MyOperation<Type1>(), new MyTotallyDifferentOperation<Type2>())
这是最简单的例子。 您可以使用上限和下限来使限制更灵活。 这可能使您能够混合类型,只要它们是兼容的(想象一个可以处理任何Number
输入的IOperation,以及提供Long
, Double
,......的不同ITotallyDifferentOperations)。 本教程解释了这一点。
添加代码后,也许你可以看看这个:
Operations<?> parameters = null;
switch (OPERATION_TYPE)
{
case TYPE_1 :
parameters = new Operations<>(new MyOperation<Type1>(),
new MyTotallyDifferentOperation<Type1>());
break;
}
switch (DB_OPERATION_TYPE)
{
case DB_TYPE_1 :
myMethod(parameters);
break;
}
static <T> void myMethod(final Operations<T> operations)
{
operations.operation.processList(operations.totallyDifferentOperation.getList());
}
static class Operations<T>
{
public final IOperation<T> operation;
public final ITotallyDifferentOperation<T> totallyDifferentOperation;
public Operations(IOperation<T> operation, ITotallyDifferentOperation<T> totallyDifferentOperation)
{
this.operation = operation;
this.totallyDifferentOperation = totallyDifferentOperation;
}
}
通过将两个操作包装到类型化参数对象中,可以确保它们属于同一类型。 这当然意味着你的dbOperations需要单独接受param对象而不是两个参数。
我假设你的Operation类和接口看起来像这样:
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());
}
编译错误的原因是myMethod()允许参数1和参数2的类型彼此不同。
最好的选择(在我看来) 不是通配符参数1和参数2,而是确保它们是相同的泛型类型,如下所示:
Operation<T> parameter1 = null;
ITotallyDifferentOperation<T> parameter2 = null;
基于IOperation接口,这些操作中的任何一个都需要myMethod()接受具有相同泛型类型的两个参数,如下所示:
void <T> myMethod(
final IOperation<T> operation,
final ITotallyDifferentOperation<T> totallyDifferentOperation) {
operation.processList(totallyDifferentOperation.getList());
}
但
如果您不想执行上述任何操作,则可以更改两个IOperation接口processList方法以接受通配符,以便您可以将所有输入保留为通配符,如下所示:
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();
}
那么唯一的问题是你在这些方法中没有任何编译时类型保证,你必须在运行时检查它们......
编辑回应Malte Hartwig:
不通配符参数将无法编译,因为T无法解析。 这就是整个问题:你不知道它是哪种类型
你不需要知道它是什么类型,只是它们是相同的类型T
我在这里扩展了我的答案:
// 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>());
至于将方法调用带入交换机并完全抛弃参数:Op澄清说这不是一个选项。
只有在我的回答发布后,Op才会回复您。 我现在已经根据我的回答编辑了它。
阐述迈克尔回答这是我提出的问题。 好像差不多 ;)
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;
}
...
另外传递描述类型参数的Class对象怎么样? 然后基本上你有非擦除类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.