c# - 两个对象相互引用可以吗?

标签 c# class oop

我正在用 C# 制作国际象棋游戏。我有 2 个类,Field 和 Piece:

public class Field
{
    // the piece that is standing on this field
    // null if no piece is standing on it
    public Piece piece { get; set; }
}

public class Piece
{
    // the field this piece is standing on
    public Field field { get; set; }
}

当一个棋子移动时,调用这个方法(在 Piece 类中):

public void Move(Field field)
{
    this.field = field;
    field.piece = this;
}

这似乎不是很好的编码,因为每次我更改字段属性时,我也必须更改该字段的 piece 属性。不过,我确实需要这两个属性,因为在我的代码的其他地方,我需要它们都进行检查等(例如,这件作品所在的领域是什么以及这个领域被哪个作品所采用)。

我的问题:这完全没问题吗,是代码味道不好还是完全错误?解决这个问题的好方法是什么?

有什么建议吗?提前致谢!

最佳答案

我在这里看到的问题是您将 Piece.fieldField.piece 作为公共(public)属性。这意味着其他人可以设置这些属性而无需更新相应的属性。

此外,当您将一个棋子从一个区域移动到另一个区域时,您不会从前一个区域移除该棋子,我们允许棋子移动到占用的方格,这将导致多个棋子引用同一区域,但该字段只会引用放置在那里的最后一 block 。

为了解决这些问题,我会将属性设置为只读(使用私有(private) setter ),强制客户端调用相应的 SetMove 方法来更改它们。然后,在这个方法中,我们可以验证我们要移动到的字段是否未被占用(如果是,我们只是抛出一个异常 - 客户端必须在调用 Move 之前先检查这一点),并且我们从 Field 中清除了 Piece

验证工作可以在 FieldPiece 类中完成,也可以在两者中完成。我将其全部放在 Field 类中以简化操作。

即便如此,这仍然存在问题。您可以直接调用 Field.SetPiece(piece)(而不是 Piece.MoveTo(field);),这将留下一个 null 字段 的值。所以这只是轻微的改进,但不是理想的解决方案。请参阅下文以获得更好的想法。

public class Field
{
    public Piece Piece { get; private set; }
    public bool Occupied => Piece != null;

    public void ClearPiece()
    {
        // Remove this field from the piece
        if (Piece?.Field == this) Piece.MoveTo(null);

        // Remove the piece from this field
        Piece = null;
    }

    public void SetPiece(Piece piece)
    {
        if (piece != null)
        {
            if (Occupied)
            {
                throw new InvalidOperationException(
                    $"Field is already occupied by {Piece}.");
            }

            // Remove piece from the piece's previous field
            if (piece.Field?.Piece == piece)
            {
                piece.Field.ClearPiece();
            }
        }

        Piece = piece;
    }
}

public class Piece
{
    public Field Field { get; private set; }

    public void MoveTo(Field field)
    {
        field.SetPiece(this);
        Field = field;
    }
}

在仔细考虑之后,我认为更好的解决方案是拥有一个处理所有验证和移动的 GameManager 类,然后我们可以制作 FieldPiece 类“哑”。

这是有道理的,因为在 Field 上设置 Piece 之前还有很多验证要做。是否可以将此棋子移动到该位置(即,如果国王处于检查状态并且这不会阻止它,那么它是不允许的)。根据棋子的移动规则,Field 是否是棋子的有效着陆点(即不允许象的水平位置)?是否有任何东西阻挡了棋子到达目的地的路径?目的地是否被同一玩家的另一 block 棋子占据?在移动一 block 之前要评估的许多事情。

此外,这将允许我们在其他类型的游戏中重用 PieceField 类,它们可能具有不同的规则集和不同的 GameManager 来执行它们。

关于c# - 两个对象相互引用可以吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54497864/

相关文章:

c# - caml 查询在 sharepoint online 中无法正常工作

c# - 向多个文本框添加属性

objective-c - @interface 可以有多个类吗?

c# - 将异步与 .Net 4 和 ms.bcl.async 一起使用

c# - 这段 C# 代码中的冒号是什么意思?

javascript - 函数何时以 }; 终止

c++ - 继承一个 C 结构并将对象指针传递给 c 函数——这安全吗?

php - 如何将对象用作数组?

php - PDO PHP MYSQL OOP 建议和操作方法

php - 使用 php 从数据库输出数据的最佳方法是什么?