我做在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;
}
这似乎并不为良好的编码,因为每次我改变字段属性,我也必须改变部分属性,用于现场。我确实需要这两个属性,但因为在我的代码的其他地方,我需要他们俩做的检查等(例如什么是这片是通过什么片场是这方面所采取)。
我的问题:这是完全正常,这是一个糟糕的代码气味或者是完全错误的?什么是解决这个好的解决办法?
有什么建议?提前致谢!
我看到这里的问题是,你有Piece.field
和Field.piece
的公共属性。这意味着,其他人可以而不更新相应的一个设置这些属性。
此外,当您从一个字段移到一块到另一个,不删除从前场一块,我们让作品搬到占领广场,这将导致多件指的是同场,但场将仅指放置在那里的最后一块。
针对这些问题,我会做的属性为只读(带私人二传手),强制客户端调用相应的Set
或Move
方法来改变它们。然后,在这个方法中,我们可以验证我们正在以不占据了场上(如果是这样,我们只是抛出一个异常 - 客户端必须调用Move
之前检查这首),以及我们从清除Piece
Field
我们的感动。
验证工作,既可以在Field
或Piece
类,或两者来完成。我把这一切在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
类,然后我们可以使Field
和Piece
类“哑巴”。
这是有道理的,因为有一个Piece
设置Field
之前做了很多更验证。它是确定移动这一块的位置(即,如果国王是在办理入住手续,这不会阻止它,那么它是不允许的)。是Field
有效的着陆点的基础上,一块的移动规则片(即一个主教水平位置将不被允许)?有没有什么阻挡件的路径到达目的地?是目标由另一片属于同一玩家占领?许多事情到移动一块之前评估。
另外,这将使我们能够重复使用其他类型的游戏,其中可能有不同的规则,和不同的Piece
强制他们Field
和GameManager
类。
没有!这涉及到循环依赖的概念。虽然施加模块,这很可能被视为前体这样。
更具体地说,这是相互递归的对象的理想例子。从概念上讲,如果替代(半伪代码)
public class Field
{
public Piece piece {
public Field field {
public Piece piece {
...
}
}
}
}
这是因为对象是在彼此的定义。那么理论上你可以这样做
this.field.piece.field.piece...