为了账号安全,请及时绑定邮箱和手机立即绑定

2个对象可以相互引用吗?

2个对象可以相互引用吗?

C#
肥皂起泡泡 2022-08-20 17:14:25
我正在用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; }}当一个棋子移动时,调用此方法(在类棋子中):public void Move(Field field){    this.field = field;    field.piece = this;}这似乎不是很好的编码,因为每次我更改字段属性时,我还必须更改该字段的 piece 属性。不过,我确实需要这两个属性,因为在我的代码的其他地方,我需要它们来执行检查等(例如,这块是什么字段,这个字段由哪一部分组成)。我的问题是:这完全没问题,是代码有难闻还是完全错误?解决这个问题的好解决方案是什么?有什么建议吗?提前致谢!
查看完整描述

2 回答

?
墨色风雨

TA贡献1853条经验 获得超6个赞

我在这里看到的问题是你有公共财产。这意味着其他人可以设置这些属性,而无需更新相应的属性。Piece.fieldField.piece


此外,当您将一个片段从一个字段移动到另一个字段时,您不会从上一个字段中删除该片段,并且我们允许片段移动到占用的正方形,这将导致多个片段引用同一字段,但该字段将仅引用放置在那里的最后一个片段。


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


验证工作可以在 或 类中完成,也可以同时在两者中完成。我把它们都放在课堂上,以简化事情。FieldPieceField


即使如此,这也存在问题。您可以直接调用(而不是 ),这将使该片段的值为 。所以这只是一个小小的改进,但不是理想的解决方案。请参阅下文以获取更好的想法。Field.SetPiece(piece)Piece.MoveTo(field);nullField


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;

    }

}

在对此进行了更多思考之后,我认为更好的解决方案是拥有一个处理所有验证和移动的类,然后我们可以使和类“愚蠢”。GameManagerFieldPiece


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


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


查看完整回答
反对 回复 2022-08-20
?
繁华开满天机

TA贡献1816条经验 获得超4个赞

不!这与循环依赖的概念有关。虽然应用于模块,但这很可能被视为此类模块的前身。


更具体地说,这是相互递归对象的理想示例。从概念上讲,如果替换(半伪代码)


public class Field

{

    public Piece piece {

        public Field field {

            public Piece piece {

                ...

            }

        }

    }

}

这是因为对象是相互定义的。然后从理论上讲,你可以做这样的事情


this.field.piece.field.piece...


查看完整回答
反对 回复 2022-08-20
  • 2 回答
  • 0 关注
  • 122 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信