【问题标题】:Serializing object with fields depending on other field序列化对象的字段取决于其他字段
【发布时间】:2016-03-10 15:15:15
【问题描述】:

假设我有一个具有给定结构的类:

class Problem {
  private String longString;
  private String firstHalf;
  private String secondHalf;
}

firstHalf 和 secondHalf 是从 longString 计算出来的,并在我的应用程序中广泛使用,但我不想序列化它们。现在,为了使这个对象的序列化工作,我需要一个 longString 的设置器。我想保护 firstHalf 和 secondHalf 是从 longString 计算的不变量,仅当 longString 存在且该值存在时才存在传递给 longString 在某种意义上是正确的,可以计算前半部分和后半部分。我目前的解决方案是让 longString 的设置器像这样编写:

public void setLongString(String value) {
  this.longString=value;
  this.firstHalf=computeFirstHalf(value);
  this.secondHalf=computeSecondHalf(value);
}

此代码还暗示 longString 与前半部分和后半部分之间的紧密相关性。

然而,让我烦恼的一件事是,setLongString 方法实际上做了三件事,而且它的名称并不能反映它的真实行为。

有没有更好的编码方式?

编辑 1: 我正在使用 Jackson 到 json 序列化程序,并且我有上半场和下半场的吸气剂,并用 @JsonIgnore 注释。

我想表达 longString 和它的一半之间的紧密耦合。

【问题讨论】:

  • 您是通过标准 java 序列化机制还是通过自定义序列化程序进行序列化?
  • 如果你想序列化一个对象,但不希望在对象中序列化特定字段,将这些字段标记为瞬态`transient String something = "";'此外,无论如何,您确实应该将所有字段设为私有并提供适当的 getter/setter 方法。然后,您可以在您的 set 方法中检查字段是否已设置并且不重置值,或任何其他有意义的业务逻辑......这是面向对象设计的一个好处
  • 我正在使用 Jackson 到 json 序列化程序。我的字段是私有的,我有 getter(被杰克逊忽略),我将编辑我的问题以表明这一点

标签: java serialization coding-style refactoring


【解决方案1】:
class Problem {
  private String longString;
  private String firstHalf;
  private String secondHalf;

  //Getters of All Variables
    ......
    ......
    ......

  // Setters of All Variables.

  public void setLongString(String longString){
     this.longString = longString;
     }

  // public but no Arguments so that user won't be able to set this Explicitly but 
  //make a call Outside of the Class to set Only and only if longString is there.

  public void setFirstHalf(){   
       if(this.longString == null)
            throw new Exception("Long String is Not Set.");
       this.firstHalf = this.computeFirstHalf(this.longString);
   }

     // public but no Arguments so that user won't be able to Set Explicitly but 
    //make a call Outside of the Class to set Only and only if longString is there.

   public void setSecondHalf(){  
       if(this.longString == null)
            throw new Exception("Long String is Not Set.");
       this.secondHalf = this.computeSecondHalf(this.longString);
   }
//private method not Accessible outside of Class
   private String computeFirstHalf(final String value){ 
     //Your Logical Code. 
    }
 //private method not Accessible outside of Class
   private String computeSecondHalf(final String value){ 
        //Your Logical Code.
}

【讨论】:

  • 当我们不需要兼容 java-beans 时看起来不错。建议的解决方案不合规(不带参数的 set* 方法)。一些框架能够接受这样的定制(对于 jackson,我们可以用 @JsonProperty 注释 compute*Half
【解决方案2】:

firstHalf 和 secondHalf 计算可以懒惰地完成(即使用 getter)

public void getFirstHalf() {
    if (this.longString != null) {
        this.firstHalf = computeFirstHalf(longString);
    }
    return this.firstHalf;
}

下半场也可以这样。

【讨论】:

  • 如果 longString 的所有值都对计算 firstHalf/secondHalf 有效,则看起来不错。如果不是这种情况,我更喜欢计算一半的 setLong 字符串。这样我们就保护了类不变量。如果 longString 不好,我们会立即失败,而不是在 getFirstHalf 调用期间失败。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-04
  • 1970-01-01
  • 2021-09-21
  • 2014-07-28
  • 2016-12-28
  • 1970-01-01
  • 2020-06-03
相关资源
最近更新 更多