这个问题的目的只是询问如何处理调用对象的方法,该方法检查与调用方法相同的条件并抛出相同的异常类型。由于问题的性质,它变成了关于课堂设计的问题。
我正在尝试国际象棋程序的课程设计。我最初创建了一个Chessboard
类,其中的方法允许您put
件。原因是:
Chessboard
界面进一步更改董事会。我创建了一个在PieceSet
构造函数中传递的可变Chessboard
类。
// Showing as interface instead of class, because implementation is not important
public interface PieceSet
{
void putBishop(Square square, Color color) throws UndefinedSquareException;
void putKing(Square square, Color color) throws UndefinedSquareException;
void putKnight(Square square, Color color) throws UndefinedSquareException;
void putPawn(Square square, Color color) throws UndefinedSquareException;
void putQueen(Square square, Color color) throws UndefinedSquareException;
void putRook(Square square, Color color) throws UndefinedSquareException;
void removePiece(Square square);
void relocate(Square fromSquare, Square toSquare) throws UndefinedSquareException;
}
在PieceSet
的实现中,方法将使用保护来检查空方块
if(null == square)
throw new UndefinedSquareException(...);
Chessboard
类将使用PieceSet
类,例如,如下所示:
public final class Chessboard
{
private PieceSet pieces;
public Chessboard()
{
this.pieces = new PieceSet();
}
public Chessboard(PieceSet initialPieces)
{
this.pieces = new PieceSet(initialPieces);
}
public Chessboard removePiece(Square square) throws UndefinedSquareException
{
/*
* Check for null here and throw exception??
* PieceSet does the same thing.
*/
PieceSet newPieces = new PieceSet(this.pieces);
newPieces.removePiece(square);
return new Chessboard(newPieces);
}
public Chessboard movePiece(Square fromSquare, Square toSquare) throws UndefinedSquareException
{
/*
* Check for null here and throw exception??
* PieceSet does the same thing.
*/
PieceSet newPieces = new PieceSet(this.pieces);
newPieces.relocate(fromSquare, toSquare);
return new Chessboard(newPieces);
}
}
接下来的问题是,由于Chessboard
也会收到Square
类型参数而且它们不应该是null
,我是否也将警卫放在Chessboard
的{{1}}中removePiece
1}}和movePiece
方法?
if(null == square)
throw new UndefinedSquareException(...);
我的另一个想法是将PieceSet
建模为Chessboard
的构建器(虽然PieceSet
可能不再是一个好名字,但我不会更改名称这个例子)。我认为,因为PieceSet
的最初想法是使用它来创建一个填充的Chessboard
,然后我会让PieceSet
负责这样做,而不是将其传递给Chessboard
。
public interface PieceSet
{
putBishop(Square square, Color color) throws UndefinedSquareException;
putKing(Square square, Color color) throws UndefinedSquareException;
// Same from above, etc. EXCEPT no remove or relocate methods
// This is new
Chessboard createBoard();
}
// The Chessboard doesn't have to use PieceSet. It can be implemented using any data structure to store pieces.
public final class Chessboard
{
private Map<Square, Piece>pieces;
public Chessboard(Map<Square, Piece> initialPieces)
{
this.pieces = new HashMap<Square, Piece>(initialPieces);
}
public Chessboard removePiece(Square square)
{
// No more duplication of checking for null square, and throwing exception
}
public Chessboard movePiece(Square fromSquare, Square toSquare)
{
// No more duplication of checking for null square, and throwing exception
}
}
答案 0 :(得分:1)
一般来说,我们强烈认为接口应该抛出一个已检查的异常。此外,我们想要装饰一个提供该接口实现的策略对象。最后,我们认为界面中的已检查异常适用于装饰器的调用者。在这种情况下,如果我们的委托抛出的异常需要传递给装饰器的调用者,那么是的,你会在装饰器中抛出同样的异常。
但是特定于Chessboard问题:我不确定我是否同意UndefinedSquareException甚至应该是一个已检查的异常。为什么这个API的用户会提供对空方块的引用,或者不是由此Chessboard管理的Square,并期望恢复?因此,我倾向于认为UndefinedSquareException扩展了RuntimeException,并且根本不需要在您的签名中,或者Chessboard从PieceSet中捕获已检查的异常并在其位置抛出RuntimeException。
希望这会有所帮助 - 喜欢阅读你的问题并思考你的问题。
答案 1 :(得分:1)
如果某个功能验证了一个也被其呼叫者验证的条件,则表明设计需要改进。特别是有几个空检查是一个糟糕的设计。这可以通过更好地安排职责来避免,有时候使用Null Object Pattern。
第一个例子中的设计似乎不必要地复杂化。 PieceSet是可变的,但每次更改时都会重新创建。为什么不把它变成第一名呢?
其次,棋盘的责任尚不清楚。所有工作都由PieceSet完成。 PieceSet知道碎片的位置,如何移动它们,如何移除它们等等。棋盘只是Middle Man。
由于这个事实,实际上Chessboard不需要防范零方块。它根本不使用Squares,并且无法识别是否传递了空方块。
你的第二个想法更容易理解,也不那么复杂。 PieceSet仅负责初始人群,并且不会在棋盘内造成持续污染。棋盘负责移动和移除碎片。明确区分关注点。
另一个建议是使用一个功能来放置像
这样的部分putPiece (Piece piece, Square square, Color color)
而不是每种类型的作品都有一个功能。通过这种方式,您可以集中验证放置,例如防止空方块。