Java 如何处理一个有时不使用某个特定变量的类

Java 如何处理一个有时不使用某个特定变量的类,java,Java,这里是初学者的问题。我正在编写一个Java程序,查询internet上的公共API以检索论坛讨论的详细信息。数据以JSON的形式返回,我正在将其解析为Java对象,以便在我的程序中使用 讨论通常包含五个属性,即五个公共变量。但是,为了响应数量有限的特定搜索类型,不会返回注释的数量 有没有一种“最佳”(就面向对象编程而言)的方法来处理这种情况?下面是我的第一次尝试,我只编写了两个构造函数,一个为numberOfComments赋值,另一个不赋值 这似乎不是一个很好的解决方案-如果另一个类创建Dis

这里是初学者的问题。我正在编写一个Java程序,查询internet上的公共API以检索论坛讨论的详细信息。数据以JSON的形式返回,我正在将其解析为Java对象,以便在我的程序中使用

讨论通常包含五个属性,即五个公共变量。但是,为了响应数量有限的特定搜索类型,不会返回注释的数量

有没有一种“最佳”(就面向对象编程而言)的方法来处理这种情况?下面是我的第一次尝试,我只编写了两个构造函数,一个为numberOfComments赋值,另一个不赋值

这似乎不是一个很好的解决方案-如果另一个类创建DiscussionDetails对象,使用不填充numberOfComments的构造函数,但随后尝试使用numberOfComments字段,会发生什么情况

我认为它可能应该分为两个类,其中DiscussionDetails没有numberOfComments字段,DiscussionDetailsSpecialized是一个带有额外numberOfComments字段的子类。为了一个领域,这对我来说有点像杀伤力过大

或者可能有一个惯例,这样一个变量是用一个特定的值初始化的,比如“false”或“-1”之类的

对于这种情况,有经验的程序员还会使用其他更好的方法吗

我知道这个例子很琐碎,但我用它来尽可能简单地说明我的问题

/**
 * Wrapper for a set of JSON data returned from an API
 */
public class DiscussionDetails 
    {
    public String discussionID;
    public String discussionName;
    public String discussionURL;
    public String submittedDate;
    public String numberOfComments;

    /**
     * Constructor that populates all fields
     */
    public DiscussionDetails(String discussionID, String discussionName, String discussionURL, String submittedDate, String numberOfComments)
        {
        this.discussionID = discussionID;
        this.discussionName = discussionName;
        this.discussionURL = discussionURL;
        this.submittedDate = submittedDate;
        this.numberOfComments = numberOfComments;
        }

    /**
     * Constructor method to use when the number of comments is unknown, which happens in certain specific cases
     */
    public DiscussionDetails(String discussionID, String discussionName, String discussionURL, String submittedDate)
        {
        this.discussionID = discussionID;
        this.discussionName = discussionName;
        this.discussionURL = discussionURL;
        this.submittedDate = submittedDate;
        } 
    }

在构造函数中调用此函数

    public class DiscussionDetails {

  public String discussionID;
  public String discussionName;
  public String discussionURL;
  public String submittedDate;
  public String numberOfComments;

  /**
   * Constructor that populates all fields
   */
  public DiscussionDetails(String discussionID, String discussionName, String discussionURL,
      String submittedDate, String numberOfComments) {
    this(discussionID, discussionName, discussionURL, submittedDate);
    this.numberOfComments = numberOfComments;
  }

  /**
   * Constructor method to use when the number of comments is unknown, which happens in certain
   * specific cases
   */
  public DiscussionDetails(String discussionID, String discussionName, String discussionURL,
      String submittedDate) {
    this.discussionID = discussionID;
    this.discussionName = discussionName;
    this.discussionURL = discussionURL;
    this.submittedDate = submittedDate;
  }
}

传统上,这是通过“特殊”值(显然没有意义的值,例如:计数为
-1
)或
null
(从某种意义上说,这是最特殊的值)来解决的


处理这一问题的“最佳”方法是,IMHO,
java.util.Optional
:客户端在希望使用某个值时必须检查该值是否存在,并且
Optional
将其明确化,避免客户端忘记检查的常见错误源。

解决这一问题的一种方法是使用生成器。您的示例很好,但构建器可以帮助您更清楚地了解正在发生的事情

/**
 * Wrapper for a set of JSON data returned from an API
 */
public class DiscussionDetails 
    {
    public String discussionID;
    public String discussionName;
    public String discussionURL;
    public String submittedDate;
    public String numberOfComments;

   public static class Builder{
      private DiscussionDetails dd = new DiscussionDetails();

      public discussionID(String discussionID) {
        dd.discussionID = discussionID;
        return this;
      }

      public discussionName(String discussionName) {
        dd.discussionName= discussionName;
        return this;
      }

      public discussionURL(String discussionURL) {
        dd.discussionURL= discussionURL;
        return this;
      }

      public submittedDate(String submittedDate) {
        dd.submittedDate= submittedDate;
        return this;
      }

      public numberOfComments(String numberOfComments) {
        dd.numberOfComments= numberOfComments;
        return this;
      }

      public DiscussionDetails build() {
        return dd;
      }

   }


 }
这可以使您的实例化更加清晰,尤其是对于可选字段或大量字段

您可以这样使用:

DiscussionDetails details = 
    new DiscussionDetails.Builder()
         .discussionID("1")
         .discussionName("Name")
         .build();
在这个特殊的例子中,我设置了两个字段。其他字段将为null或默认值。有了一些额外的代码,这给了您很大的灵活性,并且可以说使代码更易于阅读


如果需要强制设置某些字段,则可以在生成器类本身中添加更多方法,或从生成方法中抛出错误。

当给定属性没有值时,用于处理情况的“特殊”值是
null
值(
nil
在某些语言中)。然而,您应该在代码中记录这一点,以便代码的客户端知道
numberOfComments
可以是
null
——忘记它并尝试使用该值以最常见的异常之一结束-
NullPointerException

如果没有注释,则不会将
numberOfComments
设置为0就这样结束了?或者你是在试图捕捉“可能有评论,但根据我的查询我不知道”?后者。有几种不同类型的API查询用于检索讨论详细信息,例如最新讨论、特定成员提交的所有讨论、与关键字搜索匹配的一组讨论等。根据执行的查询类型,响应包含或不包含
numberOfComments
,不管讨论是否真的有评论。i、 e.尽管讨论中包含了几条评论,但API的响应完全可能没有包含评论数量的指示。这让我读到了一些关于设计模式的有趣的文章,并给了我一些作业要做,所以谢谢你!不过,我不确定这是否解决了我的问题,也就是说,我的类中有可能未设置的字段。也许我想得太多了,没有设置字段也没什么大不了的——在我看来,我的设计似乎有一点缺陷。@Hoof Hearted在一个类中设置一些未设置的字段没有什么错,尽管太多了,你可能想考虑一下模型本身。讨论对象就是一个很好的例子。例如,可能没有注释,或者用户可能没有提供URL。基本对象仍然是一样的,有两个对象,一个是discussion对象,另一个是discussionWithoutComments对象,这真的没有意义。我不知道
java.util.Optional
-谢谢你提醒我。“我会仔细阅读的。”Hoof Hearte。使用
Optional
是建模用例的唯一简单方法。使用
Optional.empty()
你会告诉客户端代码你无法确定评论的数量。我得到了一些好的回答,这些回答让我读了起来/想了想,但我接受这个答案,因为它都说明了处理特定问题的传统方式,并提供了另一种方法。这使其中一个构造函数更加简洁,并消除了一些重复,因此这似乎是一件好事,可能会改进代码。不过,我不确定它是如何回答我的问题的,除非其含义是,如果API的响应不包含
numberOfComments
元素,那么将
numberOfComments
保留为未初始化状态是可以的?@Hoof Hearted我已经说过Lombok是最小化样板代码的好方法。并使用
null
检查,因为默认情况下,所有非原语的值都为null。也许你会为discussionDetails对象使用正确的对象。像
字符串id;字符串名;一串