我有两个类,Foo1
和Foo2
,它们不是分层相关的,因此Foo1
的实例不是Foo2
的实例,也不是相反。
在与这些不同的类中,我有一个方法doStuffWithFoo
,理想情况下应该将Foo1
或Foo2
作为输入,然后相应地运行。这是我追求的基本想法:
private double[] doStuffWithFoo(Fooi foo, Bar bar1, Bar bar2, double fortyTwo) {
Fooi changingFoo = foo;
double[] fooBars = new double[N];
for (int i=0; i<N; ++i) {
double[] array = getArrayFromFoo(foo,bar1,fortyTwo);
double fooBar = getDoubleFromArray(array);
fooBars[i] = fooBar;
foo = foo.getNextFoo();
}
return fooBars;
}
我写了两种截然不同的方法
private double[] getArrayFromFoo(Foo1 foo, Bar bar, double fortyTwo)
private double[] getArrayFromFoo(Foo2 foo, Bar bar, double fortyTwo)
并且每个Foo
类都实现了自己的getNextFoo()
方法,该方法返回相同类型的Foo
。
方法getArrayFromFoo
与Foo
类没有任何关系,它从此方法所在的类中获取输入,因此创建公共接口没有意义对于Foo
s。
我认为处理这种情况的方法是:
让doStuffWithFoo
将通用对象作为输入,然后检查该类是Foo1
,Foo2
还是其他内容。这种方法的问题是我非常喜欢编译时错误来运行时错误。
编写doStuffWithFoo
的两个版本,就像我编写两个版本的getArrayFromFoo
一样。这种方法的问题在于,我将复制大量代码,这些代码在某些时候更改代码时可能会导致不一致。
还有其他选择吗?我想到的理想解决方案是,如果有一种方法可以将输入类型声明为Foo1
或Foo2
,这类似于方法1但具有即时错误。有没有办法在Java中做到这一点?
答案 0 :(得分:9)
尝试定义界面:
public interface HasDoubleArray {
public double[] getDoubleArray();
}
然后让每个Foo1
和Foo2
实现此接口,重写方法getDoubleArray()
以便以自己的特殊方式返回double[]
。然后你可以在你的导演代码中调用它:
private double[] doStuffWithFoo(HasDoubleArray hda) {
double[] array = hda.getDoubleArray();
// DO STUFF WITH array
return array;
}
答案 1 :(得分:6)
这个怎么样:
private double[] doStuffWithFoo(Foo1 foo) {
double[] array = getArrayFromFoo1(foo);
doCommonStuff(array);
return array;
}
private double[] doStuffWithFoo(Foo2 foo) {
double[] array = getArrayFromFoo2(foo);
doCommonStuff(array);
return array;
}
private void doCommonStuff(double[] array) {
// common stuff
}
答案 2 :(得分:1)
我很确定你在这里有一些更大的设计和因子问题,考虑到你给了忽必烈汗的“使用界面”答案的回答,这句话你已经说过了制成:
方法getArrayFromFoo实际上与Foo类没有任何关系,它从这个方法所在的类中获取输入,因此为Foos创建一个公共接口是没有意义的。
如果确实如此,为什么getArrayFromFoo
甚至需要将Foo1或Foo2作为参数?好吧,听起来你想要在类型上发送(即,根据你是否有Foo1或Foo2做一些不同的事情) - 但是为什么你不能通过委托做出类型适当的事情的责任来做到这一点对于有问题的类型?
我理解不希望将Foo1和Foo2中的逻辑与属于实现getArrayFromFoo
的类中的事物相关联,但是还有其他方法 - 例如,使用访问者模式以便Foo1和Foo2会用适当的事情给你回电。
此外,您对代码重复的担忧会引发更多的红旗 - 即使您最终必须编写特定于Foo1和Foo2的方法,为什么您不能将重复的部分分解为一种常用的方法?
public interface FooVisitor<T> {
public T visitFoo1(Foo1 foo1);
public T visitFoo2(Foo2 foo2);
}
public interface Foo {
public <T> T accept(FooVisitor<T> visitor);
}
public class Foo1 implements Foo {
// ...
public <T> T accept(FooVisitor<T> visitor) {
return visitor.visitFoo1(this);
}
// ...
}
public class Foo2 implements Foo {
// ...
public <T> T accept(FooVisitor<T> visitor) {
return visitor.visitFoo2(this);
}
// ...
}
public class ClientClass implements FooVisitor<Quux> {
// ...
private double[] doStuffWithFoo(Foo foo, Bar bar1, Bar bar2, double fortyTwo) {
// do common stuff...
// Now do the type-specific part
Quux whatever = foo.visit(this);
}
public Quux visitFoo1(Foo1 foo1) {
// do Foo1-specific stuff
}
public Quux visitFoo2(Foo2 foo1) {
// do Foo2-specific stuff
}
// ...
}
答案 3 :(得分:0)
我认为您的问题的原因是您不进行验证的参数:
private static void doStuffWithFoo(Fooz foo, Bar b, double d) {
Double fortyTwo;
Bar bar;
if(!foo.b().equals(b)||foo.d()!=d)
throw new IllegalArgumentException();
为此,我将按照忽必烈汗的方式使用一个界面作为参数。另外我认为你不需要2xBar参数。如果参数无法通过测试,那么我会抛出(比方说)IllegalArgumentException。你说getArrayFromFoo对类没有任何作用,所以你可以在验证后将参数传递给这个方法吗? (如果bar和double不是foo的实例(或没有逻辑)所以我认为JVM不知道属于什么)
class Foo implements Fooz{
@Override
public double d() {
// TODO Auto-generated method stub
return new Double(41);
}
@Override
public Bar b() {
// TODO Auto-generated method stub
return new Bar(41);
}
}
class Foo2 implements Fooz{
public double d() {
// TODO Auto-generated method stub
return new Double(42);
}
@Override
public Bar b() {
// TODO Auto-generated method stub
return new Bar(42);
}
}
class Bar{
Bar(int x){
this.x = x;
}
public int x;
}
interface Fooz{
double d();
Bar b();
}
public class CompareFoos{
public static void main(String[] args) {
Foo foo = new Foo();
Foo2 foo2 = new Foo2();
//doStuffWithFoo(foo2, foo2.b(), foo2.d());
doStuffWithFoo(foo2, foo.b(), foo2.d());
}
private static void doStuffWithFoo(Fooz foo, Bar b, double d) {
Double fortyTwo;
Bar bar;
//foo creates new bar for each call thats why i didnt use !foo.b().equals(b)
if(foo.b().x!=b.x||foo.d()!=d)
throw new IllegalArgumentException();
fortyTwo = d;
bar = b;
System.out.println(foo.getClass().getName() + " " + d + " " + b.x);
private double[] getArrayFromFoo(foo, bar, fortyTwo)
//more code here...
}
}