1

我经常看到有人说“如果你需要朋友/内部那么你的设计是错误的”,有人可以告诉我如何重新设计以下代码以消除 ChessPiece.Location 中的内部?

目前使用它是为了向 ChessBoard 添加棋子设置 ChessPiece.Location 属性以匹配,显然将其公开会比内部更糟糕,并且将其设为私有会阻止 ChessBoard 更新位置。感谢您的任何见解。

public struct Coord
{
   public Coord(int x, int y) { this.X = x; this.Y = y; }
   public int X { get; private set; }
   public int Y { get; private set; }
}

public class ChessBoard
{
   public ChessBoard() { /*[...]*/ }
   public ChessPiece this[int x, int y]
   {
       get
       {
           // Return ChessPiece at this position (or null)
       }
       set
       {
           // Add ChessPiece at this position and set its Location property
       }
}

public class ChessPiece
{
   public ChessPiece() { /*[...]*/ }
   public Coord Location { get; internal set; }
}
4

4 回答 4

6

我个人认为 ChessPiece 知道它的位置很奇怪——这似乎是 ChessBoard 的功能,而不是棋子本身。(棋子被拿下后在什么位置?它通常仍然是有效的棋子……)

我会将位置/移动逻辑放入 ChessBoard 中,并Dictionary<ChessPiece, Coord>为每个有效棋子的位置存储一个。

于 2009-08-16T23:23:56.920 回答
2

我的第一个想法是

  • 板子只是一个容器
  • 片具有公共只读不可变位置属性
  • 初始位置设置在块结构中
  • 通过调用棋子上的移动操作来改变位置
于 2009-08-16T23:22:17.937 回答
0

我经常看到人们说“如果您需要朋友/内部人员,那么您的设计就是错误的”

我认为这很愚蠢。朋友和内部存在于语言中是有充分理由的。

消除 ChessPiece.Location 中的内部

这样就无法更新 ChessPiece.Location。

如果 ChessPiece 对游戏有足够的了解以更新自己的位置,那就没问题了,例如:

public class ChessPiece
{
  public ChessPiece() { /*[...]*/ }
  public Coord Location { get; }
  //a measure of how good it would be to move this piece
  public int GoodnessOfBestMove
  {
    get
    {
      //calculate what self's best possible move is
      ... todo ...
    }
  }
  //an instruction to go head and do that move
  public void Move()
  {
    //do self's self-calculated best move, by updating self's private Location
    ... todo ...
  }
}

class Strategy
{
    void Move()
    {
      ChessPiece bestChessPiece = null;
      foreach (ChessPiece chessPiece in chestPieces)
      {
        if ((bestChessPiece == null) ||
          (chessPiece.GoodnessOfBestMove > bestChessPiece.GoodnessOfBestMove))
        {
          //found a better piece to move
          bestChessPiece = chessPiece;
        }
      }
      //found the best piece to move, so now tell it to move itself
      bestChessPiece.Move();
    }
}

有关更多详细信息,有一个称为“告诉不问”的 OO 原则,您可以谷歌搜索。

另一种可能性是棋盘将每个 ChessPiece 存储在棋盘拥有的二维数组中。为了移动棋子,棋盘将棋子放入阵列中的不同槽位;当一块想要报告它的位置时,它会在数组中搜索自己。

尽管以上替代方案,但我并不是说它们一定是解决这个问题的或更好的解决方案:我不认为我想将游戏策略编码为每个部分的实现细节;相反,我可能有一些非私人的方式让其他一些班级更新每件作品的位置。

于 2009-08-17T00:02:02.320 回答
0

我非常同意史蒂夫。internal 和friend 使用这种语言是有原因的,但这不一定是它的一个例子。

就我个人而言,我会在这件作品上放置一个 Move(Coord) 方法。这样,棋子就可以验证其自身移动的有效性(另外,您可以将派生类用于专门的逻辑,即用于典当与马)。Coord 应该是不可变的(坐标不移动并且应该是不可变的,块移动到一个新的坐标)。

您不应该在任何时候都在板上设置一块,这会将您对移动有效性的责任转移到您的呼叫类。如果您需要设置自定义板,请创建一个具有新起始位置的新板。

我也不同意战略方法。我确实同意这里的策略模式很好,但它不一定要内置到作品中。我会将策略移动到特定于片段的策略类中。这样,您的棋子和棋盘就简单、干净且可用于人对人游戏,并扩展用于人对 CPU 游戏

于 2009-08-17T20:49:14.590 回答