有效Java项目14:您可以’;t在不更改API的情况下更改表示

有效Java项目14:您可以’;t在不更改API的情况下更改表示,java,Java,这是来自Joshua Bloch的《有效Java》- 第14项(或第三版中的第16项):在公共类中,使用访问器方法,而不是公共字段 //像这样堕落的职业不应该公开 class Point { public double x; public double y; } 因为这些类的数据字段是直接访问的,所以这些类不会 不提供封装的好处(第13项) 如果不更改API,则无法更改表示形式 作者最后一句话是什么意思?此语句在同一项中使用多次。请建议 术语导出API或API应按照作者在本书中的建议进

这是来自Joshua Bloch的《有效Java》-

第14项(或第三版中的第16项):在公共类中,使用访问器方法,而不是公共字段

//像这样堕落的职业不应该公开

class Point {
  public double x;
  public double y;
}
因为这些类的数据字段是直接访问的,所以这些类不会 不提供封装的好处(第13项)

如果不更改API,则无法更改表示形式

作者最后一句话是什么意思?此语句在同一项中使用多次。请建议

术语导出API或API应按照作者在本书中的建议进行解释

导出的API由可访问的API元素组成 在定义API的包之外


这意味着当您有公共字段时,您的字段(表示)就是API本身,当您更改字段时,API也会更改


如果您有私有字段的公共getter,您将可以自由地使用您拥有的私有字段,并且您的API(您的公共方法)可以保持原样

作者的意思是,在不更改API的情况下,您无法更改数据的存储方式以及数据的表示方式(如您使用的容器类型)。
例如,如果决定使用point类而不是double来表示
x
y
,则需要更改类的所有使用者(更改类的API)。

API由所有公共方法和成员组成

数据成员是表示(或实现)的一部分

因此,如果将数据成员公开,更改表示也会更改API

例如,如果使用公共getter而不是公共数据成员,则可以在不更改API的情况下更改表示形式

例如,以下是使用相同API的两种不同表示形式:

class Point {
    private double x;
    private double y;

    public double getX () {return this.x;}
    public double getY () {return this.y;}
}

class Point {
    private InnerPoint p;

    public double getX () {return p.x;}
    public double getY () {return p.y;}
}

这只可能是因为数据成员是私有的(因此不是API的一部分)。

您不能重命名字段或将其更改为
私有的
,以提供封装

使用此API的代码是使用
point.x
而不是
point.getX()

如果不更改API,则无法更改表示形式

在上下文中,如果您倾向于更改定义为此类的类的属性,则表示一旦共享。如果不改变现有的API定义,这是不可行的。例如:-

class Point {
  public double x;
  public double y;

  // accessors
  double getX() { return this.x; }
  double getY() { return this.y; }
}

class Graph {

   void draw(Point point) {
       double x = point.x; // what if you decide this should be 0 if y is not 0?
}
相反,如果您在那里使用
getX()
getter,那么您可以将该逻辑作为

double getX() {
    if(p == 0) return 0;
    return this.x
}

在图中的实现中没有任何更改。

好吧,假设点类,这相当简单

class Point {
  public double x;
  public double y;
}
现在,基本上x和y是2d平面上点的表示。例如,如果决定使用它,将如下所示:

Point p;
p.x = 5;
p.y = 10;
由于x和y声明公共,因此,如果有一天您决定将点表示切换为2D平面上的半径和角度,例如

class Point {
  public double r;
  public double angle;
}
上面的代码也必须更改,这意味着使用Point对象的客户端必须重新编译它们的代码。因此,通过将x和y声明为public,您将自己限制为这些声明,现在它们是PointAPI的一部分

然而,更好的方法是将点的内部表示封装到私有点状态,并仅公开所需的功能:

class Point {
  private double x;
  private double y;

  // Computes norm2 of the point
  public double norm2() {
    return Math.sqrt(x*x + y*y);
  }
}
现在,使用Point类的用户将只能使用公共API,在这种情况下,
norm
方法,方式类似于:

Point p;
// Init coordinates
double norm = p.norm();

最后,如果您想更改内部表示,则与前面的示例相反,您的更改不会影响客户端代码。

您发布的类不是公共类。它的包裹是私人的。总的来说,你的问题不是很好clear@Xtreme好吧,OP只引用了书中那一部分的一半:)投了赞成票。但是这个类是包私有的。如果我发布API,它将不会被所有人访问。请提出建议。好吧,即使类是通道作用域,并且它的内部表示形式不会泄漏到外部,但这仍然会在同一个包中对代码施加紧密耦合,从而难以重用和重构。因此,无论类是公共的还是包作用域的,我上面的建议都是完整的。