Java 中的国际象棋 - 面向对象与效率
Chess in Java - Object orientation vs Efficiency
我正在 Java 开发一个国际象棋程序并考虑以下问题:
- Rook 部分需要实现直线移动。
- Bishop 部分需要实现沿对角线移动。
然而,
- 皇后作品需要实现上述两种移动模式。
我想不出一个干净的解决方案来为这种关系建模,我考虑了一些,但 none 它们都符合良好的面向对象设计 和 代码高效。
Java不支持多重继承,所以Queen不能借用Rook和Bishop的实现
如果 Rook 和 Bishop 扩展了 Queen,我需要将每种移动的逻辑提取到单独的方法中,这会严重膨胀我当前关于如何验证移动的设计。
以上解决方案都不够优雅,无法击败:
- 将所有运动实现放入所有部件的父级 class 中,这样它们就可以共享 all 通用实现(其中有相当多)
我知道解决方案 3 违反了良好的 Java 设计,但在这种情况下,该设计模式似乎只会强制采用臃肿、不优雅的解决方案。
可能这可以通过完全重组程序来避免,但到目前为止的一切对我来说看起来都非常有效,良好的 OO 设计是否总是以功能和结构的直接性为代价?是不是我的方法不适合语言风格?
你会如何解决这个问题?
Java doesn't support multiple inheritance, so Queen cannot borrow implementation from Rook and Bishop
您不需要多重继承。很多都可以用默认方法模拟。
您可以将这两个方法移至超类,但将它们设为 protected static
(您也可以将这些方法放在 PieceHelper
中)。然后在子类中,您可以实现适当的方法,引用这些方法中的一个或另一个(使它们 public
)。
超类:
abstract class Piece {
protected static void moveStraight(Piece p) {...}
protected static void moveDiagonal(Piece p) {...}
}
(可选)接口:
interface DiagonalMover {
void moveDiagonal();
}
interface StraightMover {
void moveStraight();
}
子类:
class Rook extends Piece implements StraightMover {
public void moveStraight() {Piece.moveStraight(this);}
}
class Bishop extends Piece implements DiagonalMover {
public void moveDiagonal() {Piece.moveDiagonal(this);}
}
class Queen extends Piece implements StraightMover, DiagonalMover {
public void moveStraight() {Piece.moveStraight(this);}
public void moveDiagonal() {Piece.moveDiagonal(this);}
}
虽然一些 classes 可能以类似的方式运行,但这并不自动意味着它们在一个层次结构中!
例如,Human
和Crab
都可以横向移动,但是Human
扩展Crab
是愚蠢的。
如果你真的想重复使用移动代码,你可以使用封装,使用 Movement
类型并像这样:
class Human
{
List<Movement> movements;
}
class Crab
{
List<Movement> movements;
}
class MoveSideWays extends Movement
{
move();
}
class MoveForward extends Movement
{
move();
}
但这感觉像是过度设计。我会用 Piece
class 和 getPossibleMoves()
直接实现它。没有太多重叠,Rooks 也有专门的动作(Casling)。
class Rook extends Piece
{
List<Move> getPossibleMoves() {...}
}
class Queen extends Piece
{
List<Move> getPossibleMoves() {...}
}
你不应该对单个片段添加超class-子class关系。 Queen 不是 Rook 的特例,Rook 也不是 Queen 的特例。它们只是不同的部分。您可以创建一个接口(或抽象 class)Piece
并提供不同的实现,如 Rook
、Bishop
、Queen
等。
直线和对角线运动是行为
因此,可以使用比继承更合适的接口对它们进行建模
Rookie 实现 StraightMovement
Bishiop 实现 DiagonalMovement
Queen 实现 StraightMovement、DiagonalMovement
我正在 Java 开发一个国际象棋程序并考虑以下问题:
- Rook 部分需要实现直线移动。
- Bishop 部分需要实现沿对角线移动。
然而,
- 皇后作品需要实现上述两种移动模式。
我想不出一个干净的解决方案来为这种关系建模,我考虑了一些,但 none 它们都符合良好的面向对象设计 和 代码高效。
Java不支持多重继承,所以Queen不能借用Rook和Bishop的实现
如果 Rook 和 Bishop 扩展了 Queen,我需要将每种移动的逻辑提取到单独的方法中,这会严重膨胀我当前关于如何验证移动的设计。
以上解决方案都不够优雅,无法击败:
- 将所有运动实现放入所有部件的父级 class 中,这样它们就可以共享 all 通用实现(其中有相当多)
我知道解决方案 3 违反了良好的 Java 设计,但在这种情况下,该设计模式似乎只会强制采用臃肿、不优雅的解决方案。
可能这可以通过完全重组程序来避免,但到目前为止的一切对我来说看起来都非常有效,良好的 OO 设计是否总是以功能和结构的直接性为代价?是不是我的方法不适合语言风格?
你会如何解决这个问题?
Java doesn't support multiple inheritance, so Queen cannot borrow implementation from Rook and Bishop
您不需要多重继承。很多都可以用默认方法模拟。
您可以将这两个方法移至超类,但将它们设为 protected static
(您也可以将这些方法放在 PieceHelper
中)。然后在子类中,您可以实现适当的方法,引用这些方法中的一个或另一个(使它们 public
)。
超类:
abstract class Piece {
protected static void moveStraight(Piece p) {...}
protected static void moveDiagonal(Piece p) {...}
}
(可选)接口:
interface DiagonalMover {
void moveDiagonal();
}
interface StraightMover {
void moveStraight();
}
子类:
class Rook extends Piece implements StraightMover {
public void moveStraight() {Piece.moveStraight(this);}
}
class Bishop extends Piece implements DiagonalMover {
public void moveDiagonal() {Piece.moveDiagonal(this);}
}
class Queen extends Piece implements StraightMover, DiagonalMover {
public void moveStraight() {Piece.moveStraight(this);}
public void moveDiagonal() {Piece.moveDiagonal(this);}
}
虽然一些 classes 可能以类似的方式运行,但这并不自动意味着它们在一个层次结构中!
例如,Human
和Crab
都可以横向移动,但是Human
扩展Crab
是愚蠢的。
如果你真的想重复使用移动代码,你可以使用封装,使用 Movement
类型并像这样:
class Human
{
List<Movement> movements;
}
class Crab
{
List<Movement> movements;
}
class MoveSideWays extends Movement
{
move();
}
class MoveForward extends Movement
{
move();
}
但这感觉像是过度设计。我会用 Piece
class 和 getPossibleMoves()
直接实现它。没有太多重叠,Rooks 也有专门的动作(Casling)。
class Rook extends Piece
{
List<Move> getPossibleMoves() {...}
}
class Queen extends Piece
{
List<Move> getPossibleMoves() {...}
}
你不应该对单个片段添加超class-子class关系。 Queen 不是 Rook 的特例,Rook 也不是 Queen 的特例。它们只是不同的部分。您可以创建一个接口(或抽象 class)Piece
并提供不同的实现,如 Rook
、Bishop
、Queen
等。
直线和对角线运动是行为 因此,可以使用比继承更合适的接口对它们进行建模
Rookie 实现 StraightMovement
Bishiop 实现 DiagonalMovement
Queen 实现 StraightMovement、DiagonalMovement