我目前正在编写抽象代码,这些代码可以处理任何网格结构上的操作。为了代替具体的方法,我一直在尝试开发一个框架,该框架接受lambda表达式并提供基于网格元素之间的方向关系的功能,但在尝试将泛型类型返回到这些方法时遇到了麻烦。
我有一个像下面这样的工作方法,它接受一个lambda函数来查找特定方向上的网格元素,并接受一个Consumer来对每个元素执行一些方法。
public static <E> void forEachClockwise(Direction d, Function<Direction, ? extends E> f, Consumer<? super E> c){
/*For each of the orthogonal directions, in order:*/
c.accept(f.apply(d));
/*end For*/
}而不是每次调用这个方法时都要传递一个元素查找函数,我决定让一个‘正交’接口声明这样一个函数,并重载forEachClockwise方法来接受这个接口的元素会更好。
public static <O extends Orthogonal> void forEachClockwise(Direction d, O center, Consumer<O> c){
forEachClockwise(d, center::findNextByDirection, c);
}我在这里使用了泛型并进行了声明,以便Consumer方法能够在不强制转换的情况下访问网格元素的字段。我担心这是一个糟糕的设计选择,因为尽管尝试了一些不同的东西,但我创建的正交接口和测试类并没有在没有警告和强制转换的情况下进行编译。
public interface Orthogonal {
public <E extends Orthogonal> E findNextByDirection(Direction a);
}我尝试过的两个findNextByDirection的“有效”实现是:
/* in Coordinate implements Orthogonal: */
@Override
public <E extends Orthogonal> E findNextByDirection(Direction a) {
return (E) (/*The proper Coordinate*/);
}和
@Override
public Coordinate findNextByDirection(Direction a) {
return /*The proper Coordinate*/;
}
//Warning on return type declaration:
/*Type safety: The return type Element for findNextByDirection(Direction) from the type Element needs unchecked conversion to conform to E from the type Orthogonal*/最好,我希望有一个forEachClockwise (和其他方法)可以接受的方法,它返回调用它的同一个类的一个元素,而不进行类型转换。坐标的findNextByDirection应该返回一个坐标,地址应该返回一个地址,单元格应该返回一个单元格,等等。我看过的其他问题和答案讨论了如何使用泛型返回类型的方法,但我还没有找到任何关于如何将这种方法用作lambda参数的提示。
有几件事我还没有尝试过,那就是创建一个新的findByDirection方法,它接受某种正交类型和一个方向作为参数,或者使用正交中定义的一些方法调用forEachClockwise方法,尽管这些方法听起来和我尝试的一样合理。我所见过的另一种可行的方法是为接口提供自己的泛型类型,但是将每个正交类声明为"MyClass implements“显然是错误的,也是不符合目的的
我是不是从一开始就完全错误地设计了这个接口,并期望泛型能做一些它们设计时没有考虑到的事情?或者,有没有一种更简单的方法来让类调用正确的方法并返回自己类型的元素?
完整代码:
package test;
import java.util.function.Consumer;
import java.util.function.Function;
public enum Direction {
NORTH, EAST, SOUTH, WEST;
public static <O extends Orthogonal> void forEachClockwise(Direction d, O center, Consumer<O> c){
forEachClockwise(d, center::findNextByDirection, c);
}
public static <X> void forEachClockwise(Direction d, Function<Direction, ? extends X> f, Consumer<? super X> c){
c.accept(f.apply(d));
forEachExcept(d, f, c);
}
public static <X> void forEachExcept(Direction d, Function<Direction, ? extends X> f, Consumer<? super X> c){
for(int i=0; i<3; i++){
d = Direction.getClockwise(d);
c.accept(f.apply(d));
}
}
public static Direction getClockwise(Direction d){
switch(d){
case EAST:
return SOUTH;
case NORTH:
return EAST;
case SOUTH:
return WEST;
case WEST:
return NORTH;
default:
return null;
}
}
}
interface Orthogonal {
public <E extends Orthogonal> E findNextByDirection(Direction a);
}
class Coordinate implements Orthogonal{
int x;
int y;
public Coordinate(int x, int y){
this.x = x;
this.y = y;
}
public int getX(){
return x;
}
public int getY() {
return y;
}
@Override //Warning on "Coordinate" below. Compiler suggests writing
//entire <E extends Orthogonal> method signature
public Coordinate findNextByDirection(Direction a) {
switch(a){
case NORTH:
return new Coordinate(x+1, y);
case SOUTH:
return new Coordinate(x-1, y);
case EAST:
return new Coordinate(x, y+1);
case WEST:
return new Coordinate(x, y-1);
default:
return null;
}
}
}https://stackoverflow.com/questions/41366170
复制相似问题