说我有这段代码:
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;
...
接受interfaces
和MyOperation
实施的两个MyTotallyDifferentOperation
的方法:
void myMethod(final IOperation<?> operation, final ITotallyDifferentOperation<?> totallyDifferentOperation) {
operation.processList(totallyDifferentOperation.getList());
}
totallyDifferentOperation.getList()
返回的List<T>
与List<T>
接受的operation.processList()
类型相同。
此代码显然无法编译。
是否有其他模式可以获得相同的结果,或者可以更正此代码?
根据要求,我发布了更多的方法。不幸的是,我不能再透露,这是一个模型。
我需要这种模式以避免重复代码。
答案 0 :(得分:4)
没有既定的设计模式可以帮助你。
您的问题出在这些变量的声明中:
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;
}
}
通过使用通配符,您实际上是在告诉编译器&#34;我不关心类型&#34;。那不是真的。最后你会关心这种类型。
从根本上说,你的方法试图做太多,而这是导致你出现问题的原因。将其分解为多种方法,它变得更加容易:
---
- hosts: local
connection: local
become: yes
become_user: root
tasks:
- name: add docker's key
apt_key:
keyserver: hkp://p80.pool.sks-keyservers.net:80
id: 58118E89F3A912897C070ADBF76221572C52609D
- name: add deb repo
file: path=/etc/apt/sources.list.d/docker.list state=touch
- name: register apt sources
lineinfile: dest="/etc/apt/sources.list.d/docker.list" line="{{item}}"
with_items:
- "deb https://apt.dockerproject.org/repo ubuntu-trusty main"
- name: install docker-engine
apt: name=docker-engine state=present update-cache=yes force=yes
答案 1 :(得分:2)
阅读this Java tutorial about generic method parameters。您可以向方法添加类型参数,以确保操作和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。 This tutorial解释了这一点。
添加代码后,也许您可以查看一下:
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对象而不是两个参数。
答案 2 :(得分:1)
我假设您的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());
}
<强> BUT 强>
如果您不想执行上述任何操作,则可以将两个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澄清说这不是一个选项。
只有在我的回答发布后,才会对此作出回应澄清。我现在已经根据我的回答编辑了它。
答案 3 :(得分:0)
阐述迈克尔回答这是我的想法。 似乎几乎很好;)
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;
}
...
答案 4 :(得分:0)
如何另外传递描述类型参数的Class对象?那么你基本上就有了非擦除类型。