当委托方法具有相同的防范时,如何处理保护条款和抛出异常?

时间:2013-12-07 23:32:35

标签: java oop

这个问题的目的只是询问如何处理调用对象的方法,该方法检查与调用方法相同的条件并抛出相同的异常类型。由于问题的性质,它变成了关于课堂设计的问题。

我正在尝试国际象棋程序的课程设计。我最初创建了一个Chessboard类,其中的方法允许您put件。原因是:

  1. 它是不可变的,我想多次创建新的板对象只是为了初始化它似乎没必要。
  2. 理想情况下,董事会应该填充一次,并且应通过Chessboard界面进一步更改董事会。
  3. 我创建了一个在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
        }
    }
    

2 个答案:

答案 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)

而不是每种类型的作品都有一个功能。通过这种方式,您可以集中验证放置,例如防止空方块。