将经典代码更改为功能代码
Changing classic code to functional
我有以下 丑陋 (但有效)代码的一部分,用于检查棋盘上的字段是否为空:
if (abs(xDst - xSrc) == abs(yDst - ySrc)) {
boolean backslashMove = xSrc < xDst && ySrc > yDst || xSrc > xDst && ySrc < yDst;
if (backslashMove) {
int y = max(ySrc, yDst) - 1;
for (int x = min(xSrc, xDst) + 1; x < max(xSrc, xDst); x++) {
if (board.getActiveChessmanAt(x, y).isAlive()) {
return false;
}
y--;
}
} else { //slash move
显然,它会检查类似 Bishop 的移动线中坐标 (xScr, ySrc) 和 (xDst, yDst) 之间的字段。
我正在尝试使用 IntStream 对此进行转换:
if (backslashMove) {
final int y = max(ySrc, yDst) - 1;
if (IntStream.range(min(xSrc, xDst) + 1, max(xSrc, xDst))
.anyMatch(x -> board.getActiveChessmanAt(x, y).isAlive()))
return false;
在这种情况下,我该如何执行 y-- ?如果要在 'anyMatch' 命令
中使用,它必须是最终的
如果你真的需要使用流重写它,那么你可以利用x
和y
同时递增的事实。所以你可以构建一个增量的范围而不是x-values的范围:
final int xSrc = min(xSrc, xDst) + 1;
final int xDst = max(xSrc, xDst);
final int ySrc = max(ySrc, yDst) - 1;
if (IntStream.range(0, xDst - xSrc)
.anyMatch(distance -> board.getActiveChessmanAt(xSrc + distance, ySrc + distance).isAlive())) {
return false;
}
一般来说, 不可能直接使用 "parent" 方法中的 non-final 局部变量。 Java 不支持 真正的闭包 。为此,您需要一个包装器对象(AtomicInteger
是一个经常被推荐的候选对象),或者您可以将 non-final 变量设为一个 class 字段(注意潜在的线程安全问题)。就我个人而言,这两个 "tricks" 都不好。
您需要的不是 streams/folds 方面的函数式编程。
相反,您应该重构您的实际代码以使其成为 clearer/shorter/better。
例如,您可以:
把散落在实际方法中的逻辑部分提取到具体方法中有意义的名字
使用结构化对象而不是太精细的单一变量
删除不需要的嵌套:使用提前退出和不需要的条件语句可能会有所帮助
它可以给:
// -> extract method + structured objects
if (!isPointsMatch(pointSrc, pointDst)) {
return false; // -> early exit
}
// -> extract method + structured objects
if (isBackslashMove(pointSrc, pointDst)) {
if (board.hasAnyActiveChessmanAlive(pointSrc, pointDst)) {
return false;
}
}
// else slash move -> The else is useless
// ...
您截取的原始代码是程序。您的功能方法效果不佳。那么 面向对象 方法怎么样?
class Position{
private final int x, y;
public Position(int x, int y){
this.x=x;
this.y=y;
}
public getX(){
return x;
}
public getY(){
return y;
}
}
interface Move {
Position moveFrom(Position start);
}
interface Figure {
Collection<Move> getPossibleMoves(Position start, Board board);
}
class Bishop implements Figure {
private final Collection<Move> moves = new HashSet<>();
public Bishop(){
moves.add(start->new Position(start.getX()-2,start.getY()-1));
moves.add(start->new Position(start.getX()-2,start.getY()+1));
moves.add(start->new Position(start.getX()+2,start.getY()-1));
moves.add(start->new Position(start.getX()+2,start.getY()+1));
moves.add(start->new Position(start.getX()-1,start.getY()-2));
moves.add(start->new Position(start.getX()-1,start.getY()+2));
moves.add(start->new Position(start.getX()+1,start.getY()-2));
moves.add(start->new Position(start.getX()+1,start.getY()+2));
}
@Override
public Collection<Move> getPossibleMoves(Position start, Board board){
return moves.stream()
.filter({ Position end = m.moveFrom(start);
return board.isOnBorad(end.getX(),end.getY())
&& board.getActiveChessmanAt(end.getX(), end.getY()).isAlive()})
.collect(Collectors.toSet());
}
}
Figure
的另一个实现可能 return 每个步骤的单独 Move
实例,直到达到限制:
class Tower implements Figure {
enum Direction {
NORTH(1,0),EAST(0,1),SOUTH(-1,0),WEST(0,-1);
private final Position change;
private Direction(int x, int y){
change = new Position(x, y);
}
public Position getNextFrom(Position start){
return new Position(start.getX()+change.getX(),start.getX()+change.getY());
}
@Override
public Collection<Move> getPossibleMoves(Position start, Board board){
Collection<Move> moves = new HashSet<>();
for(Direction direction : Direction.values()){
Position current = direction.getNextFrom(start);
while( board.isOnBorad(current.getX(),current.getY())
&& board.getActiveChessmanAt(current.getX(), current.getY()).isAlive()){
moves.add(p-> new Position(current.getX(),current.getY());
}
}
return moves;
}
}
我有以下 丑陋 (但有效)代码的一部分,用于检查棋盘上的字段是否为空:
if (abs(xDst - xSrc) == abs(yDst - ySrc)) {
boolean backslashMove = xSrc < xDst && ySrc > yDst || xSrc > xDst && ySrc < yDst;
if (backslashMove) {
int y = max(ySrc, yDst) - 1;
for (int x = min(xSrc, xDst) + 1; x < max(xSrc, xDst); x++) {
if (board.getActiveChessmanAt(x, y).isAlive()) {
return false;
}
y--;
}
} else { //slash move
显然,它会检查类似 Bishop 的移动线中坐标 (xScr, ySrc) 和 (xDst, yDst) 之间的字段。
我正在尝试使用 IntStream 对此进行转换:
if (backslashMove) {
final int y = max(ySrc, yDst) - 1;
if (IntStream.range(min(xSrc, xDst) + 1, max(xSrc, xDst))
.anyMatch(x -> board.getActiveChessmanAt(x, y).isAlive()))
return false;
在这种情况下,我该如何执行 y-- ?如果要在 'anyMatch' 命令
中使用,它必须是最终的如果你真的需要使用流重写它,那么你可以利用x
和y
同时递增的事实。所以你可以构建一个增量的范围而不是x-values的范围:
final int xSrc = min(xSrc, xDst) + 1;
final int xDst = max(xSrc, xDst);
final int ySrc = max(ySrc, yDst) - 1;
if (IntStream.range(0, xDst - xSrc)
.anyMatch(distance -> board.getActiveChessmanAt(xSrc + distance, ySrc + distance).isAlive())) {
return false;
}
一般来说, 不可能直接使用 "parent" 方法中的 non-final 局部变量。 Java 不支持 真正的闭包 。为此,您需要一个包装器对象(AtomicInteger
是一个经常被推荐的候选对象),或者您可以将 non-final 变量设为一个 class 字段(注意潜在的线程安全问题)。就我个人而言,这两个 "tricks" 都不好。
您需要的不是 streams/folds 方面的函数式编程。
相反,您应该重构您的实际代码以使其成为 clearer/shorter/better。
例如,您可以:
把散落在实际方法中的逻辑部分提取到具体方法中有意义的名字
使用结构化对象而不是太精细的单一变量
删除不需要的嵌套:使用提前退出和不需要的条件语句可能会有所帮助
它可以给:
// -> extract method + structured objects
if (!isPointsMatch(pointSrc, pointDst)) {
return false; // -> early exit
}
// -> extract method + structured objects
if (isBackslashMove(pointSrc, pointDst)) {
if (board.hasAnyActiveChessmanAlive(pointSrc, pointDst)) {
return false;
}
}
// else slash move -> The else is useless
// ...
您截取的原始代码是程序。您的功能方法效果不佳。那么 面向对象 方法怎么样?
class Position{
private final int x, y;
public Position(int x, int y){
this.x=x;
this.y=y;
}
public getX(){
return x;
}
public getY(){
return y;
}
}
interface Move {
Position moveFrom(Position start);
}
interface Figure {
Collection<Move> getPossibleMoves(Position start, Board board);
}
class Bishop implements Figure {
private final Collection<Move> moves = new HashSet<>();
public Bishop(){
moves.add(start->new Position(start.getX()-2,start.getY()-1));
moves.add(start->new Position(start.getX()-2,start.getY()+1));
moves.add(start->new Position(start.getX()+2,start.getY()-1));
moves.add(start->new Position(start.getX()+2,start.getY()+1));
moves.add(start->new Position(start.getX()-1,start.getY()-2));
moves.add(start->new Position(start.getX()-1,start.getY()+2));
moves.add(start->new Position(start.getX()+1,start.getY()-2));
moves.add(start->new Position(start.getX()+1,start.getY()+2));
}
@Override
public Collection<Move> getPossibleMoves(Position start, Board board){
return moves.stream()
.filter({ Position end = m.moveFrom(start);
return board.isOnBorad(end.getX(),end.getY())
&& board.getActiveChessmanAt(end.getX(), end.getY()).isAlive()})
.collect(Collectors.toSet());
}
}
Figure
的另一个实现可能 return 每个步骤的单独 Move
实例,直到达到限制:
class Tower implements Figure {
enum Direction {
NORTH(1,0),EAST(0,1),SOUTH(-1,0),WEST(0,-1);
private final Position change;
private Direction(int x, int y){
change = new Position(x, y);
}
public Position getNextFrom(Position start){
return new Position(start.getX()+change.getX(),start.getX()+change.getY());
}
@Override
public Collection<Move> getPossibleMoves(Position start, Board board){
Collection<Move> moves = new HashSet<>();
for(Direction direction : Direction.values()){
Position current = direction.getNextFrom(start);
while( board.isOnBorad(current.getX(),current.getY())
&& board.getActiveChessmanAt(current.getX(), current.getY()).isAlive()){
moves.add(p-> new Position(current.getX(),current.getY());
}
}
return moves;
}
}