静态常量是否违反"encapsulation"?
Does static constants violate "encapsulation"?
好的,所以我正在使用这本书:核心 Java 第一卷——基础知识。
封装定义如下:
Encapsulation (sometimes called information hiding) is a key concept
in working with objects. Formally, encapsulation is simply combining
data and behavior in one package and hiding the implementation details
from the users of the object.
在SO里查了一下,知道封装和信息隐藏是两个独立的概念,是结合在一起使用的。但是,为了这个问题,让我们坚持书中的定义(说封装==实现隐藏),因为这个问题使用了书中的例子。
public class Math
{
. . .
public static final double PI = 3.14159265358979323846;
. . .
}
书上说这不会破坏封装,因为它是一个常量。但是上面的代码不会破坏封装的 实现隐藏 部分(根据本书的定义),因为 PI 不仅对 class 可见,而且对程序的其余部分可见。
我的问题实际上可能与此重复:Does a public static const variable break the encapsulation ideology?(虽然用 C++ 标记)但答案说它确实违反了封装(与书相矛盾),这没关系。我知道我的问题是否因为这个可能的重复问题而被关闭
编辑:我只是 post 另一个示例代码作为评论提到的 PI 不被视为实现细节
public class System
{
. . .
public static final PrintStream out = . . .;
. . .
}
我认为静态不符合 OOP 原则。所以既不违也不守。
静态文字不是任何对象的一部分,它们只是分配给全局变量的数据以供说服。
因此,这本身并没有违反封装,而是完全没有面向对象。
OOP 方法是根本没有全局常量,而是定义一个对象来解决您的问题。
interface Figure {
double perimeter();
}
class Circle implements Figure {
private final double radius;
@Override
public double perimeter() {
return this.radius * 2 * (float) 3.1416926;
}
}
以下是关于该主题的更多讨论:
https://www.yegor256.com/2015/07/06/public-static-literals.html
好问题。我不认为你提供的例子破坏了封装,至少严格来说是这样。
你给出的第一个例子是常量 PI,第二个例子是提供对 System 中 out 常量的访问的例子;大概是为了利用一些代码,例如 System.out.println("HelloWorld!");
。正如其他人已经提到的,PI
实际上只是一个常量,常量的用户无法修改或影响该值。 PI
的用户仍然需要在他们的代码中引用常量(构成这里的 API)。如果 PI
被修改(不太可能,但谁知道呢)用户将不会受到该更改的影响,因为无论如何他们都需要重新编译代码。
考虑封装的一个有用方法是考虑为了违反封装需要什么。 Effective Java 第 3 版在第 16 项中很好地描述了这一点,建议如果没有适当的封装“你不能在不改变 API 的情况下改变表示,你不能强制不变量,你不能采取访问字段时的辅助操作。"
一个非常明显的违反上述内容的是下面的 class(也在 Effective Java 的第 16 项中):
class Point {
public double x;
public double y;
}
所有字段都是 public,此 API 的用户将被迫直接使用这些字段。如果后来作者决定在可以访问或修改 x
或 y
之前添加一些验证检查,那么在不破坏现有客户端的情况下就不可能这样做。 API 必须进行重大修改,并且可能会破坏下游用户的行为。
现在让我们看看您提供的第二个示例:
public class System
{
. . .
public static final PrintStream out = . . .;
. . .
}
这看起来与上面 PI
的示例非常相似,但有一个关键区别:所讨论的字段是 PrintStream。虽然 out
字段本身是此 API 的明确部分,现在可能很难更改(现在它已公开,客户将使用并依赖它),但 PrintStream
类型是一个 class,这实际上是这里有趣的地方:用户将在 class 上引用方法。这里我们有 PrintStream
的 API 中的关键功能,可以在不中断使用的情况下随着时间的推移而发展。将来也有可能将 out
常量更改为引用不同的 PrintStream
subclass 并且 API 的用户应该不受影响。
希望对您有所帮助。
好的,所以我正在使用这本书:核心 Java 第一卷——基础知识。
封装定义如下:
Encapsulation (sometimes called information hiding) is a key concept in working with objects. Formally, encapsulation is simply combining data and behavior in one package and hiding the implementation details from the users of the object.
在SO里查了一下,知道封装和信息隐藏是两个独立的概念,是结合在一起使用的。但是,为了这个问题,让我们坚持书中的定义(说封装==实现隐藏),因为这个问题使用了书中的例子。
public class Math
{
. . .
public static final double PI = 3.14159265358979323846;
. . .
}
书上说这不会破坏封装,因为它是一个常量。但是上面的代码不会破坏封装的 实现隐藏 部分(根据本书的定义),因为 PI 不仅对 class 可见,而且对程序的其余部分可见。
我的问题实际上可能与此重复:Does a public static const variable break the encapsulation ideology?(虽然用 C++ 标记)但答案说它确实违反了封装(与书相矛盾),这没关系。我知道我的问题是否因为这个可能的重复问题而被关闭
编辑:我只是 post 另一个示例代码作为评论提到的 PI 不被视为实现细节
public class System
{
. . .
public static final PrintStream out = . . .;
. . .
}
我认为静态不符合 OOP 原则。所以既不违也不守。
静态文字不是任何对象的一部分,它们只是分配给全局变量的数据以供说服。
因此,这本身并没有违反封装,而是完全没有面向对象。
OOP 方法是根本没有全局常量,而是定义一个对象来解决您的问题。
interface Figure {
double perimeter();
}
class Circle implements Figure {
private final double radius;
@Override
public double perimeter() {
return this.radius * 2 * (float) 3.1416926;
}
}
以下是关于该主题的更多讨论: https://www.yegor256.com/2015/07/06/public-static-literals.html
好问题。我不认为你提供的例子破坏了封装,至少严格来说是这样。
你给出的第一个例子是常量 PI,第二个例子是提供对 System 中 out 常量的访问的例子;大概是为了利用一些代码,例如 System.out.println("HelloWorld!");
。正如其他人已经提到的,PI
实际上只是一个常量,常量的用户无法修改或影响该值。 PI
的用户仍然需要在他们的代码中引用常量(构成这里的 API)。如果 PI
被修改(不太可能,但谁知道呢)用户将不会受到该更改的影响,因为无论如何他们都需要重新编译代码。
考虑封装的一个有用方法是考虑为了违反封装需要什么。 Effective Java 第 3 版在第 16 项中很好地描述了这一点,建议如果没有适当的封装“你不能在不改变 API 的情况下改变表示,你不能强制不变量,你不能采取访问字段时的辅助操作。"
一个非常明显的违反上述内容的是下面的 class(也在 Effective Java 的第 16 项中):
class Point {
public double x;
public double y;
}
所有字段都是 public,此 API 的用户将被迫直接使用这些字段。如果后来作者决定在可以访问或修改 x
或 y
之前添加一些验证检查,那么在不破坏现有客户端的情况下就不可能这样做。 API 必须进行重大修改,并且可能会破坏下游用户的行为。
现在让我们看看您提供的第二个示例:
public class System
{
. . .
public static final PrintStream out = . . .;
. . .
}
这看起来与上面 PI
的示例非常相似,但有一个关键区别:所讨论的字段是 PrintStream。虽然 out
字段本身是此 API 的明确部分,现在可能很难更改(现在它已公开,客户将使用并依赖它),但 PrintStream
类型是一个 class,这实际上是这里有趣的地方:用户将在 class 上引用方法。这里我们有 PrintStream
的 API 中的关键功能,可以在不中断使用的情况下随着时间的推移而发展。将来也有可能将 out
常量更改为引用不同的 PrintStream
subclass 并且 API 的用户应该不受影响。
希望对您有所帮助。