【问题标题】:Can encapsulation be achieved in Java with getter and setter methods that are not public?可以在 Java 中使用不公开的 getter 和 setter 方法实现封装吗?
【发布时间】:2021-06-05 05:24:21
【问题描述】:

据我了解,封装(在 Java 中)是一种将相关数据和方法包装到对象中的机制,数据对其他类隐藏,只能通过当前类的方法访问(又名数据隐藏),如果我错了,请纠正我。

在阅读一些教程时,我看到他们指定 getter 和 setter 方法应该是公共的。

我明白为什么它不应该是私有的,但为什么不保护或默认?使用受保护的或默认的 getter 和 setter 方法是否仍算作封装?

【问题讨论】:

  • 限制访问使其“更加封装”,而不是更少。不过,除此之外 - getter 和 setter 将向“某人”隐藏实现。你想隐藏整个包的实现吗?你想隐藏子类的实现吗?这完全取决于您要达到的目标。不同的属性甚至可能会有所不同;例如,如果它是一个简单的值,为什么还要使用样板 getter?

标签: java oop encapsulation


【解决方案1】:

访问器当然可以受到保护。例如,抽象基类可能会使用受保护的 getter 向子类公开一些内部状态,而该 getter 不是消费者应该使用的 API 的一部分。

也就是说,getter 和 setter 通常在 JavaBeans 的上下文中使用,其中 getter 和 setter 定义对象的属性。如果它们不是公开可见的,那么虽然它们仍然提供封装,但它们并不能用于特定目的。

您正在阅读的教程是从某个对象的用户(开发人员)的角度编写的。此类属性需要公开才能完成工作,并且大多数属性访问器都是公开的。

【讨论】:

    【解决方案2】:

    封装是为了防止其他对象直接修改值。

    如果您将 getter 和 setter 设为私有,则只有该类中的其他方法才能调用它们。这可能是因为您想验证该值,或者因为您想确保支持多线程或其他一些问题。

    如果你让它们受到保护,那么继承和扩展类将能够调用它们,但没有其他类,甚至你的 main 方法也不能调用 getter 和 setter。

    如果您只想公开值,没有什么可以阻止您拥有受保护/私有 setter 和公共 getter,或者根本没有 setter(您必须在另一个方法或构造函数中实例化该值)

    【讨论】:

      【解决方案3】:

      Java 中的封装是通过将类的字段设为private 来实现的。通过将它们设为protected 来实现更弱的封装。

      Getter 和 setter 方法不实现封装。相反,它们为与封装数据进行某些类型的交互提供了一种机制。如果未封装数据,则不需要 getter 和 setter 方法。因此,当然,您可以提供受保护或默认访问的 getter 和 setter,甚至是私有的。或者根本没有。这完全取决于您希望您的班级向谁展示哪些功能。

      将 getter 和 setter 公开是因为它们提供了使用类所必需的功能,而不是因为该级别的访问权限是封装的要求。

      【讨论】:

      • 也许你会发现修改后的措辞更令人满意,@JanezKuhar。我可以看到以前的阅读方式可能与新的不同。
      • 您说“通过保护它们来实现更弱的封装”,这是否也适用于默认字段?
      • @piny88,从技术上讲,我想我不得不说“是”,因为默认访问提供了受保护访问的严格子集。但我确实认为,子类访问其超类的成员与同一个包中的其他类这样做在性质上是不同的。
      【解决方案4】:

      在阅读一些教程时,我看到他们指定 getter 和 setter 方法应该是公共的。

      这通常在教程中完成,因为它更容易编写,同时还提供“某种面向对象的感觉”,因为您仍然可以使用 getter 和 setter 进行一些控制。

      您也可以(不推荐)使用公共字段并完全省略 setter 和 getter:

      public class Foo {
        public int i;
        public String s;
      }
      

      但是当使用 setter 时,您可以例如验证数据:

      public class Foo {
        public void set(int temperature) {
          if(temperature < 273) throw new IllegalArgumentException();
          this.temperature = temperature;
        }
      }
      

      但是,如果您需要一次验证多个值怎么办?使用 setter,您只能始终验证当前值,但不能同时验证多个 setter 调用。这是公共设置者不好的一种情况。

      另一件事是:面向对象的编程非常注重名称:setXYZ 你说的不多。例如setTemperature 可能适合恒温器。但就是这样。也许你甚至得到了更高级的东西:setTemperatureLevel(值 1-5)然后设置内部desiredTemperature,当这个值高于你想要设置heater 到true 的当前温度时。

      使用简单的设置器时,您无法控制是否所有这些步骤都按正确的顺序完成,或者是否跳过了某些步骤。但是使用 setLevel 方法在类中完成所有这些操作,没有办法搞砸方法调用者。

      当然,在 Java 世界中,这些公共 setter 和 getter 非常方便:在许多框架中,例如将数据库映射到 DAO 或用于 JSON 反/序列化的 DTO,它使事情变得更容易。因为这里它被用作读取和写入对象字段的约定。这些对象通常称为 JavaBeans。

      但是当涉及到您的域对象时,我强烈建议您将不希望其他人访问和/或操纵的所有内容保密。

      【讨论】:

        猜你喜欢
        • 2019-01-30
        • 2018-05-05
        • 1970-01-01
        • 1970-01-01
        • 2017-04-10
        • 1970-01-01
        • 1970-01-01
        • 2016-08-04
        • 1970-01-01
        相关资源
        最近更新 更多