【问题标题】:Setters and getters with composition in Java在 Java 中具有组合的 Setter 和 getter
【发布时间】:2020-04-12 19:41:23
【问题描述】:

当 Java 使用组合而不是继承时,我对 Java 中的 setter 和 getter 有疑问。 我在解决大学作业时产生了这种疑问。

假设我有 2 个课程:汽车和电池。 Battery 有 3 个变量(var1、var2、var3)以及 getter 和 setter。

汽车类是这样的:

public class Car {
  private String color;
  private String model;
  private Battery battery;

  public Car(String color, String model, Battery battery) {
    this.color = color;
    this.model = model;
    this.Battery = new Battery(battery);
  }

  public getBattery() {
    return new Battery(battery);
  }

  public void setBattery(Battery battery) {
    this.battery = new Battery(battery.getVar1(), battery.getVar2(), battery.getVar3());
    //or this.battery = battery;
  }

我知道 getter 方法的原因(因为它与对象的引用有关),但是 setter 方法呢? 我尝试在网络上查找 Udemy 的 Java 课程(来自 Tim Buchalka),但我没有看到这个问题。

有人可以帮帮我吗?谢谢!

【问题讨论】:

  • 请澄清您不清楚的问题
  • 我认为对于 setter 方法也是同样的原因。但是,我不建议您执行这样的实现,因为复制实例并不直接(而且这也不是常见的做法)。
  • @Nithin 我对 setter 的怀疑是,每次我在网络示例中看到一个对象的 setter 时,它总是类似于“this.battery = battery”。但是在我这个大学学科的pdf文件上,那里的例子和我放的一样。我知道您正在重新定义对象的 3 个变量,但我怀疑是否因为引用的东西而按照我写的方式更好,或者是否有其他原因(如良好做法或其他)。
  • @Lenon 是的,这就是重点。在这门大学科目上我必须这样做,否则我的成绩会低一点。考虑到我在互联网上的任何地方都没有看到这样的实现,我只想 100% 理解其中的原因。
  • 看看immutability

标签: java oop composition


【解决方案1】:

Car 类中的三个方法中的每一个都在生成 Batterydefensive copy。这可以防止Car 之外的任何其他对象更改Car 内部的Battery,因为没有其他对象会引用该特定Battery 实例(因为它总是被复制)。

习语new Battery(battery) 被称为复制构造函数,因为它利用构造函数来克隆对象。是防御性抄袭的常见属性。

【讨论】:

  • 谢谢!我很难得到它,现在我明白了。此外,我不知道我现在要研究的那个概念(防御性复制)。
【解决方案2】:

就其实现方式而言,我不同意这种格式。更好的做法是编写 this.battery = battery 并保留它(而不是像问题中那样创建一个新对象并分配其变量)。

【讨论】:

    【解决方案3】:

    您的代码在某些地方看起来很奇怪,我已将其更改为我期望的样子:

    public class Car {
      private String color;
      private String model;
      private Battery battery;
    
      public Car(String color, String model, Battery battery) {
        this.color = color;
        this.model = model;
    
        //Now, we're setting Car.battery to the battery that you passed in. 
        //Previously, you were passing the battery instance back into the Battery constructor.
        this.battery = battery;
        //this.battery = new Battery(battery); 
      }
    
      public getBattery() {
        //We want to return the battery we have above, not a new battery
        return battery;
        //return new Battery(battery);
      }
    
      public void setBattery(Battery battery) {
        //You wouldn't do this. Just use the line you've commented out.
        //No need to remake a new Battery object when you already have one passed in.
    
        this.battery = new Battery(battery.getVar1(), battery.getVar2(), battery.getVar3());
        //or this.battery = battery;
      }
    

    setter 方法的意义何在?在您已经构建汽车之后,它可以设置/更改汽车实例中电池的值。而您将使用构造函数在构造过程中设置电池。

    【讨论】:

      【解决方案4】:

      当您创建一个电池副本并将其存储时,您就可以使汽车类免受突变的影响。

      突变的意思是,假设您将给定的电池对象作为输入存储在 setter 方法中,然后在某处您对同一个电池对象进行更改,然后您无意中更改了先前创建的汽车类中的电池对象可能不打算作为该更改的一部分,因此为避免此类问题,您可以使用此方法,以便汽车中电池对象的值仅通过 setter 方法或构造函数更改。

      我希望这可以帮助您理解为什么他们希望在 setter 方法中创建额外的对象

      【讨论】:

      • 谢谢!就是这样,我很难得到这个。
      【解决方案5】:

      当您将私有对象(在本例中为 Battery)作为您的类中的属性时,一般的经验法则是您需要 getter 和 setter。 getter 和 setter 需要返回私有对象的副本,这样就不会违反信息隐藏。否则,你可以这样做:

      Car c1 = new Car(...);
      ...
      Battery b1 = new Battery(var1, var2, var3);
      c1.setBattery(b1);  // if setBattery doesn't make a copy, 
                          // then the private variable battery in c1 
                          // is the same reference as b1
      
      b1.changeOneOfTheValues(); // I change b1, and now my private variable 
                                 // in c1 is also changed!
      

      【讨论】:

      • 对于我 10 多年的专业经验,我从未见过这样的实现。考虑看看projectlombok.org/features/GetterSetter
      • @lenon 不确定如何远程推广 Project Lombok 以解决原始发帖人提出的任何问题。最初的问题想知道为什么设置器复制而不是仅仅这样做。电池=电池。
      • 这个库非常受欢迎,我认为他们不需要我的推广,我只是将它们作为常见做法的示例(因为它们非常受欢迎)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多