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>());