【问题标题】:Checking the validity of a variable before calling the super constructor在调用超级构造函数之前检查变量的有效性
【发布时间】:2017-06-30 00:03:51
【问题描述】:

所以我正在编写一些代码,其中涉及扩展一个我之前编写的类,在该类中创建文件并使用构造函数命名,该构造函数接受名称和大小为 long 类型。在那个原始类中,我在构造函数中验证输入的文件名包含一个“。”字符,但不需要文件上的特定扩展名。对于我正在编写的这个新类,我要求名称的扩展名为“.mp3”。但是,我的编译器不喜欢在超级构造函数之前进行验证。

这是我当前的代码:

public class Song extends DigitalMedia{

private String artist;
private String album;
private String name;
private long size;

public Song(String aName, long aSize, String aArtist, String aAlbum){
    super(aName, aSize);
    setArtist(aArtist);
    setAlbum(aAlbum);
}

在我创建构造函数之前,有什么方法可以验证“aName”是否包含“.mp3”?

【问题讨论】:

  • @J Zane 我建议你研究一下构造函数调用层次结构以及为什么它的设计方式必须首先调用超类构造函数。当我们学习时,我们不应该只是消化事实,而是应该尝试找到答案,为什么会这样,如果不是这样会发生什么错误。另外我建议你研究一下如果构造函数抛出异常会发生什么。我试图在我的回答中对这些事情做一些说明,stackoverflow.com/a/42179930/504133

标签: java class constructor extends super


【解决方案1】:

我不能说这是否是设计程序的最佳方式,但您可以在 super 参数之一中调用验证器方法:

public Song(String aName, long aSize, String aArtist, String aAlbum){
    super(validateName(aName), aSize);
    setArtist(aArtist);
    setAlbum(aAlbum);
}

private static String validateName(String name) {
    if (whatever) {
        throw new Whatever();
    }
    return name;
}

【讨论】:

    【解决方案2】:

    到达constructor 的代码执行意味着对象是活动的,现在准备好初始化其states(字段)。

    A.java 类的对象也可以称为A.java 的超类的对象。在A.java 类初始化状态之前,对象从超类继承属性和特性是有意义的。超类完成初始化后,A.java 就有机会进行初始化。

    如果超类中存在无参数构造函数,则隐式调用超类的构造函数,否则您需要显式调用超类的任何一个参数化构造函数。

    如果constructor 中的条件失败,您希望做什么?您可以选择抛出异常但仍然创建对象,您可以通过覆盖finalize() 方法并检查this 对象来验证相同的情况。您可能希望通过调用System.gc() 来影响垃圾收集器,以便让代码执行更快地到达finalize() 方法。

    建议的解决方案 您应该在调用构造函数之前验证构造函数的参数。如果您想将它封装在您的类中,那么您可以选择添加一个非私有静态方法(您可能希望将其命名为getInstance())创建并返回类Song 的对象。在这种情况下,您可以将构造函数设为私有。请注意,这将使您的类不可扩展,这只是一种设计选择。

    【讨论】:

      【解决方案3】:

      另一种解决方案是通过内置类型检查来强制执行您的规则。

      你可以创建一个MediaFormat:

      interface MediaFormat { }
      

      实现MediaFormatMusicFormat,允许您指定支持的音乐格式:

      enum MusicFormat implements MediaFormat {
          MP3("mp3");
      
          private final String format;
      
          MusicFormat(String format) {
              this.format = format;
          }
      
          @Override
          public String toString() {
              return format;
          }
      }
      

      DigitalMedia 可以由 MediaFormat 组成:

      class DigitalMedia {
          private final MediaFormat format;
          private final String name;
      
          public DigitalMedia(String name, MediaFormat format) {
              this.name = name;
              this.format = format;
          }
      }
      

      Song 可以接受MusicFormat

      class Song {
          public Song(String name, MusicFormat format) {
              super(name, format);
          }
      }
      

      这将强制用户使用MusicFormat 中指定的任何内容,避免所有这些讨厌的检查。然后,您可以公开一个返回 name + "." + formatString 方法

      【讨论】:

      • 我认为这是最好的选择。强类型化使您可以在编译时处理错误,而其他解决方案需要在运行时处理错误,这通常更困难并且使代码更复杂。当然,如果MusicFormat 是从字符串创建的,您还需要运行时错误处理,但此解决方案允许将该问题与歌曲创建分开。
      • @MickMnemonic 这是一个常量,不需要运行时检查。唯一的问题是,如果他错误地声明了常量,那么运行时检查将无济于事。你能详细说明一下吗?
      • 看起来 OP 正在从某处获取文件扩展名作为输入,因此需要在运行时处理 MusicFormat.valueOf(inputString)
      【解决方案4】:

      从继承的角度来看,子类实际上不应该比它的超类更具限制性。

      但如果你想让子类的实例化更受限制,你可以让构造函数private 并提供一个首先进行验证的工厂方法。

      public class Song extends DigitalMedia {
      
          private String artist;
          private String album;
          private String name;
          private long size;
      
          private Song(String aName, long aSize, String aArtist, String aAlbum) {
              super(aName, aSize);
              setArtist(aArtist);
              setAlbum(aAlbum);
          }
      
          public static Song makeSong(String aName, long aSize, String aArtist, String aAlbum) {
              //... validation code
              return new Song(aName, aSize, aArtist, aAlbum);
          }
          ...
      }
      

      您使用封装来强制执行不变量,而不是限制类型本身。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-07-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多