与Java的公共领域有什么关系?

Ann*_*nan 22 java oop

我一直在javaworld.com上阅读两篇文章(1)(2),关于所有类字段应该是私有的,getter/setter方法也同样糟糕.对象应该对其拥有的数据起作用,而不是允许访问它.

我目前正在为Connect Four进行大学任务.在设计程序时,玩游戏的代理商需要访问董事会的状态(因此他们可以决定要移动的内容).他们还需要将此移动传递给游戏,以便将其验证为合法移动.在决定移动内容时,将各个部分分组为具有起点和终点的威胁.

Board,Threat和Point对象实际上并没有做任何事情.它们只是存储可以以人类可读方式访问的相关数据.

在设计之初,我将板上的点表示为两个元素int数组,但是在创建点或引用它们的组件时会很烦人.

所以,班级:

public class Point {
    public int x;
    public int y;
    public Point(int x, int y){
        this.x = x;
        this.y = y;
    }
}
Run Code Online (Sandbox Code Playgroud)

我能想到的各方面都很完美.除了它打破了我学到的每一条规则.我犯了罪吗?

mer*_*ike 18

公共字段将对象的表示暴露给其调用者,即如果表示必须改变,则调用者也是如此.

通过封装表示,您可以强制调用者如何与其进行交互,并且可以更改该表示,而无需在公共API未更改的情况下修改调用者.在任何非平凡的程序中,封装都是实现合理可维护性所必需的.但是,虽然您需要胶囊,但它们的适当粒度可能比单个类大.例如,IteratorCollection它操作的内部表示中封装一个是没有意义的.

有了这个,让我们看看你的例子:

public class Point {
    public int x;
    public int y;
    public Point(int x, int y){
        this.x = x;
        this.y = y;
    }
}
Run Code Online (Sandbox Code Playgroud)

该类的内部表示极不可能改变,因此通过将字段设为私有来隐藏表示的结构没有任何好处.但是,我会阻止调用者Point在构造之后修改它:

public class Point {
    public final int x;
    public final int y;
    public Point(int x, int y){
        this.x = x;
        this.y = y;
    }
}
Run Code Online (Sandbox Code Playgroud)

这样一个实际上希望封装其状态的类可以在Point泄漏其内部表示的情况下返回它,并在其表示中使用给定的Point而不捕获它.这也非常适合一个点的数学概念,它没有身份或改变状态.

在设计程序时,玩游戏的代理商需要访问董事会的状态(因此他们可以决定要移动的内容).他们还需要将此移动传递给游戏,以便将其验证为合法移动.在决定移动内容时,将各个部分分组为具有起点和终点的威胁.

Board,Threat和Point对象实际上并没有做任何事情.它们只是存储可以以人类可读方式访问的相关数据.

现在这听起来像是一个浪费的封装机会:代理人真的不应该被允许任意修改董事会,但仅限于法律行动.为什么Game在更新的国家居于课堂时,决定法律行动是什么Board?如果Board要验证移动本身,没有调用者,特别是没有代理,可能违反游戏规则:

public class Board {
    // private fields with state

    // public methods to query state

    public void perform(Move move) throws IllegalMoveException;
}
Run Code Online (Sandbox Code Playgroud)


Jam*_*mes 12

将一个字段公开并不总是一件坏事,但是你严格限制自己,因为你将实现与使用它的类耦合起来.稍后你想要添加一个监听器,只要设置了X中的值,就会通知你.没有重构一切,你无法做到这一点.如果实现setX()并隐藏字段本身,则只需更改setX()的实现即可通知您已对使用此方法的类进行了更改而未对其进行更改.

  • +1 重构/侦听器:澄清一点,在企业开发中,对象通常基于方法名称和字段(JavaBean 规范)进行反映。它基本上是属性的 Java 版本——人们对它有不同的看法(他们都是对的)。关于这个主题的一个有趣的观点是 lombok 项目,他们使用注释和创造性编译作为解决这个常见问题的一种方式。我不推荐它用于家庭作业,但它有助于快速开发。 (2认同)
  • 值得注意的是,这种重构可以由任何体面的Java IDE自动执行 - 前提是您可以访问所有调用者的源代码. (2认同)

Rom*_*nko 5

如果您知道界面不会改变,那么将变量公之于众是完全合法的.问题是随着程序变得越来越复杂,您需要更改对字段的访问权限,但现代IDE使重构变得容易,所以我想说继续.


pm1*_*100 5

这是c#优于Java的一个优点.你可以宣布一个有公共领域的类,然后改变你的想法使用带有getter和setter的隐藏字段; 但是调用者的语法是一样的

public class Point
{
     public int X;
}
Run Code Online (Sandbox Code Playgroud)

public class Point
{
     int m_x;
     public int X {get {return m_x;} set {m_x = value;}
}
Run Code Online (Sandbox Code Playgroud)

但来电者总是如此

Point p;
p.X = 12;
Run Code Online (Sandbox Code Playgroud)

  • 虽然对于您自己的代码是正确的,但这对于库来说是不可接受的,因为属性和字段的二进制接口是不同的,因此这是对.dll库的重大更改. (2认同)