Java - 使用受保护的方法从不同的 class 更新对象的属性

Java - Update attributes of an object from a different class with protected methods

我正在尝试交换网格中的片段(或单元格)。

我有 class 具有坐标(在板上的位置)等属性的单元格。此 class 具有受保护的方法 setCoordinate。

我还有class关卡,有棋盘等属性(由classCell的很多物体组成),还有换棋子的方法。它还具有类似 getCell 的方法,用于在给定网格中的坐标的情况下检索单元格对象。

所以,如果我创建一个单元格对象,例如:

Cell cell1 = (Cell) getCell(new Coordinate(2, 2));
Cell cell2 = (Cell) getCell(new Coordinate(1, 1));

当我交换棋子时

    public void swapCells(Coordinate firstCoord, Coordinate secondCoord) {
          setCell(secondCoord,getCell(firstCoord));
          setCell(firstCoord,getCell(secondCoord));
}

我可以将单元格 1 放在单元格 2 的位置,将单元格 2 放在单元格 1 的位置。但是,每个单元格的坐标不会根据板中的新位置更新。

我无法使用 class 单元格中的 setCoordinate 方法,因为它受到保护,而且我无法创建 public 方法。我不确定原因,但我仍在学习,这是给定的要求。

如何实现坐标也更新的交换?

以下是我的代码的一些相关和简化部分:

public class Level {
   
    private Cell[][] board;

   
    public Level(String fileName) {
       
        parse(fileName);
    }

 
    private void parse(String fileName) {
        ... fills board...
    }

   

    public Cell getCell(Coordinate coord) {
        return board[coord.getRow()][coord.getColumn()];
        } 
   

    private void setCell(Coordinate coord, Cell cell) {
        
            board[coord.getRow()][coord.getColumn()] = cell;       
    }

    public void swapCells(Coordinate firstCoord, Coordinate secondCoord) {
        
            setCell(secondCoord,getCell(firstCoord));
            setCell(firstCoord,getCell(secondCoord)); 
        } 
    }
}


public class Cell {

    private Coordinate coordinate;

    public Cell(int row, int column) {
        setCoordinate(row,column);
    }

    public Coordinate getCoordinate() { return this.coordinate; }

    protected void setCoordinate(int row, int column) {
        this.coordinate = new Coordinate(row,column);
    }

}


public class Coordinate {
    private int row;
    private int column;

    public Coordinate(int row, int column) {
        setRow(row);
        setColumn(column);
    }

    public int getRow() { return this.row; };

    private void setRow(int row) {
        this.row = row;
    }

    public int getColumn() {return this.column; }

    private void setColumn(int column) {
        this.column = column;
    }

}

编辑: 仔细研究之后,我的问题似乎是,当我进行交换时,我将一块新棋子分配给棋盘中的一个单元格,而不是真正交换。最终的棋盘是正确的,但我一直在重新创建棋子而不是交换棋子。

所以,稍微简化一下,将 (0,0) 中的片段与 (1,1) 中的片段交换,我这样做:

board[0][0] = getCell(1,1);
board[1][1] = getCell(0,0);

但是我正在为选定的位置创建新作品。

我测试的是这样的:

Cell cell1 = getCell(0,0);
Cell cell2 = getCell(1,1);

swapCells(cell1.getCoordinate(), cell2.getCoordinate());

assertEquals("(1,1)", cell1.getCoordinate().toString());

但是 assertequals 失败了,因为它们在这些对象 cell1 和 cell2 上,但我并没有真正使用这些对象,只是创建了看起来像它们的新对象。此外,swapCells 方法没有 Cell 对象作为参数。我真的不知道该怎么做。

您有两个问题需要解决。

  1. 更改 Cell 对象在 board 数组中的位置。
  2. 交换时更新 Cell 对象的内部数据。

第一个你已经完成了。要达到第二个,您至少需要能够执行以下选项之一。

  1. 可以访问更新数据的方法,或者
  2. 有一个可以为您更新数据的委托对象,或者
  3. 给人一种发生交换的错觉,或者
  4. 使用反射(不推荐)

您提到您受到给定要求的限制,您不能更改对所需方法的访问。因此,这不是一个选项。

创建委托对象(在此上下文中)意味着您将需要扩展 Cell class 并允许通过子 class 访问其受保护的方法。这对我来说似乎是一个黑客。我不认为这是执行此操作的正确方法,但它允许您在不真正违反您的要求的情况下进行访问。

第三个选项是我认为你应该做的。为此,您需要做的就是创建原始对象的副本并将它们放在需要去的地方。例如,将单元格二的副本放在单元格一所在的位置,将单元格一的副本放在单元格二所在的位置。

第四个选项我就不解释了。但是,使用反射,您将能够绕过访问限制并操作受保护的数据。如果你愿意,你可以阅读反射。但是,不管我个人对反思的看法如何,它都是一个可以让你实现你想要的东西的选择。

UPDATE:交换数组中的两个元素时,需要执行这个简单的 3 步过程:

  1. 将元素 1 存储在临时变量中。
  2. 将元素 2 存储在元素 1 的位置。 (元素 2 变为元素 1)
  3. 将 TEMPORARY 变量存储在元素 2 的位置(旧元素 1 变为元素 2)。

如果您不将第一个元素存储到临时变量中,您将覆盖第一个元素的数据。在您的情况下,它看起来像这样:

public void swapCells(Coordinate firstCoord, Coordinate secondCoord) {
    
    Cell temp = getCell(secondCoord); // Saves second cell temporarily

    setCell(secondCoord, getCell(firstCoord)); // Saves first cell into second cell's location
    setCell(firstCoord, temp); // Sets the temp cell (second cell) into the first cell's location
}

此外,因为您可以访问 Cell 对象,所以即使该方法受到保护,您也可以设置坐标。因此,您的 setter 方法应该是这样的:

private void setCell(Coordinate coord, Cell cell) {
    
    cell.setCoordinate(coord.getRow(), coord.getColumn());
    board[coord.getRow()][coord.getColumn()] = cell;
}

我在 Cell class 中添加了一个“名称”属性,以便于调试(对您而言)。现在,当我 运行 你的代码和我所做的两个更改时,你可以看到以前是 (0,0) 的“cell0”现在是 (2,2) 而 cell8 现在是 (0,0) ;显示这两个单元格交换了位置并更新了它们各自的坐标字段。

我为此执行的 main 方法如下:

public static void main(String[] args) {
    Level level = new Level("Level1");
    int count = 0;
    for (int row = 0; row < 3; row++) {
        for (int col = 0; col < 3; col++ ) {
            Coordinate coordinate = new Coordinate(row, col);
            Cell cell = new Cell(row, col, "cell" + count++);
            level.setCell(coordinate, cell);
        }
    }
    
    level.swapCells(new Coordinate(0,0), new Coordinate(2,2));
}