它是确定这两个对象相互引用?

问题描述 投票:4回答:2

我做在C#中的棋局。我有2班,现场和海贼王:

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;
}

这似乎并不为良好的编码,因为每次我改变字段属性,我也必须改变部分属性,用于现场。我确实需要这两个属性,但因为在我的代码的其他地方,我需要他们俩做的检查等(例如什么是这片是通过什么片场是这方面所采取)。

我的问题:这是完全正常,这是一个糟糕的代码气味或者是完全错误的?什么是解决这个好的解决办法?

有什么建议?提前致谢!

c# class oop
2个回答
3
投票

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

此外,当您从一个字段移到一块到另一个,不删除从前场一块,我们让作品搬到占领广场,这将导致多件指的是同场,但场将仅指放置在那里的最后一块。

针对这些问题,我会做的属性为只读(带私人二传手),强制客户端调用相应的SetMove方法来改变它们。然后,在这个方法中,我们可以验证我们正在以不占据了场上(如果是这样,我们只是抛出一个异常 - 客户端必须调用Move之前检查这首),以及我们从清除Piece Field我们的感动。

验证工作,既可以在FieldPiece类,或两者来完成。我把这一切在Field类把事情简单化。

即便如此,也有这个问题。您可以直接调用Field.SetPiece(piece)(而不是Piece.MoveTo(field);),这将留下一块与null一个Field值。所以,这只是一个轻微的改善,而不是理想的解决方案。请参阅下面的一个更好的主意。

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类“哑巴”。

这是有道理的,因为有一个Piece设置Field之前做了很多更验证。它是确定移动这一块的位置(即,如果国王是在办理入住手续,这不会阻止它,那么它是不允许的)。是Field有效的着陆点的基础上,一块的移动规则片(即一个主教水平位置将不被允许)?有没有什么阻挡件的路径到达目的地?是目标由另一片属于同一玩家占领?许多事情到移动一块之前评估。

另外,这将使我们能够重复使用其他类型的游戏,其中可能有不同的规则,和不同的Piece强制他们FieldGameManager类。


0
投票

没有!这涉及到循环依赖的概念。虽然施加模块,这很可能被视为前体这样。

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

public class Field
{
    public Piece piece {
        public Field field {
            public Piece piece {
                ...
            }
        }
    }
}

这是因为对象是在彼此的定义。那么理论上你可以这样做

this.field.piece.field.piece...
© www.soinside.com 2019 - 2024. All rights reserved.