5

我正在编写一个小游戏,我有两个课程:BoardPiece. Board(到目前为止)有一个Piece可以在Board.

public class Board {
  private Piece piece_;
  private int width, height;
  ...

  movePieceDown() {
    piece_.moveTo(this, 1, 2);
  }
}

public class Piece {
  public boolean moveTo(Board board, int x, int y) {
    // move piece to new location (x,y)
    // return true if successful
  }
}

piece_.moveTo(this, 1, 2);如果我通过参考 Board是否是不好的方法,这样如果 Board 上没有障碍物,Piece 可以移动到新位置?如果没有传递对 Board 的引用,Piece 不知道新位置是否有障碍物,或者它是否超出了 Board 边界。

在我看来,每个对象都应该只关心自己:Piece 应该移动到新位置,Board 应该担心它是否合法移动,但是我发布的这个示例代码更有意义并简化了事情。

TL;DR:我是在将对象本身传递给字段的方法时违反了一些 OOP 准则,还是一些普通的 OOP 习语?预先感谢您向我澄清这一点。

4

7 回答 7

8

这不是一个坏方法。传递this给各种方法在编程中并不少见。这仅取决于您的设计,就我而言,Piece课堂上什么都没有。

课堂上的一件事Board可能会令人困惑 -movePieceDown方法。你有不可用的参数Board board。如果您打算将其this用作参数,请删除该属性,因为该板不应该接收其他板作为潜在参数,并且事实上,不应该知道其他板可以存在。

最后,您可以确保Piece将接口Board视为方法参数,并确保该协定永远不会改变。例如,它可能有以下方法:

public interface IBoard { 
    public boolean isFieldFree(int x, int y)
    public Piece getPiece(int x, int y) 
}

无论您以后如何更改 Board 的实现,这应该始终有效,因此您不必Piece在更改Board. 这样你就可以强制执行一个Piece不能改变你的棋盘状态的规则(在界面中,不要公开任何改变棋盘状态的方法)。

于 2013-06-26T12:00:20.433 回答
3

首先,为什么你的 piece 变量以下划线结尾?这很奇怪:p

至于你的问题。我会处理所有与片段相关的事情,例如在片段类中移动。如果您想知道您在棋盘上的位置,我将在您的棋子类中有 2 个整数变量,称为 x 和 y。

该棋子不必知道它是否会与棋盘上的其他棋子发生碰撞,因为这是您的棋盘类在移动棋子时应该处理的事情。

因此,例如,如果您将棋子移动到 x = 1 和 y = 2,您应该让棋盘检查位置 1,2 是否已经有棋子并做出相应的响应。

将“this”传递给另一个类的方法并没有错,但从松散耦合的面向对象编程的角度来看,这不是最佳设计。

只是我的 2 美分 :)

于 2013-06-26T12:04:01.147 回答
2

我认为这是一个很好的策略,尤其是当您需要将一堆局部变量传递给一个方法时。与其传递所有这些本地变量,不如传递对象的实例来整理您的方法签名。

只需确保进行良好的封装,以便接收此参数的方法不会修改字段或调用旨在具有受限访问权限的方法。

于 2013-06-26T12:02:58.333 回答
2

一般来说,通过this并不少见,但要视情况而定。在这种情况下是否是上帝取决于实现细节。ABoard有几个可以四处移动的管道,所以位置是一块的属性。然而,将一块棋子从一个位置移动到另一个位置可能是棋盘的一项功能。例如,如果新位置已被占用,会发生什么?然后该棋子会移动其他棋子吗?这是否适合您的设计?

根据您在棋子上的签名,我希望 moveTo 函数接受一个棋盘,这向我表明棋子可以从一个棋盘移动到另一个棋盘。阅读代码时,这可能会产生误导,除非确实如此。

于 2013-06-26T12:05:30.163 回答
1

我不确定你是否会通过这样做来阻止任何面向对象的编程规则,但这看起来确实很奇怪,因为你在 a 上调​​用一个方法Board,然后这个方法唯一做的就是调用一个Piece将自己作为参数传递的方法.

面向对象的编程非常注重将事物视为现实世界中的对象。按照这种方法,我会看它好像棋子在棋盘上,例如它的位置是由棋盘决定的,而不是由棋盘本身决定的。从这种方法来看,移动棋子是在棋盘上完成的,而不是棋子本身。

所以,即使this作为参数传递并不正确,我宁愿定义方法:

public class Board
{
    private Piece p;
    // ...

    public boolean movePieceDown()
    {
        // Move the piece to a new location using it's setters
    }
}

此外,使用这种方法,由于Board对象知道它的属性,因此生成的代码将更具可读性,因为您不必调用这么多 getter 和 setter(例如检查边界)。

于 2013-06-26T12:08:10.970 回答
1

只回答标题中的具体问题(而不是关于 OO 设计的一般意见):不,这不是坏习惯,而是很常见。

但是,请注意,this不建议在构造函数中传递给外部世界,因为它可能会在并发场景中导致令人讨厌的错误,其中接收者可能会看到源处于不一致的状态。

于 2013-06-26T12:13:45.577 回答
0

这是通过普通方法调用隐式传递的。阅读我在论坛上找到的这个答案。

您也可以为此阅读JVM 规范

于 2013-06-27T12:21:18.193 回答