java - build 者的最后障碍

标签 java immutability builder final

我有一个使用生成器(J Bloch 样式)的图形 (g)。需要反转图表以运行某些统计信息,然后将这些统计信息缓存起来以供报告和分析算法访问。

因此,图 g 定义了以下引用变量:

private final Builder savedBuilder; // save builder for clone build with same properties.
private final Graph   gPrime;       // must reverse populated graphs BEFORE cache of stats

注意:gPrime 指的是一个相同的图,只是它是由反向 g 填充的。 gPrime.gPrime 应该引用 g,因为 g 是 gPrime 的反义词。

和构建器构建方法:

public Graph build() {
  Graph g = new Graph(this);
  g.gPrime.gPrime = g;
  return g;
}

以及采用构建器的构造函数:

private Graph (Builder builder){  // 'this' used for clarity
  this.gType        = builder.gType;
  this.dropOrphans  = builder.dropOrphans;
  this.fileHandle   = builder.fileHandle;       
  this.nodes        = builder.nodes;            
  this.edges        = builder.edges;            
  this.delimiter    = builder.delimiter;
  this.mapCapacity  = builder.mapCapacity;       
  this.mapLoadFactor    = builder.mapLoadFactor;
  this.savedBuilder = builder;  // save builder for cloning

  emptyGraph();     // build empty structure for data in this graph
  if (this.fileHandle == null) {           // no file data
    if (this.nodes == 0) {         // no sizing info
    ;                  // nothing else to do - - - empty graph
    } else {                    // we have # of nodes
      if ( this.edges == 0) {            // just an edge-less integer graph)
      populateEdgeless(nodes)   ;
      } else {                 // randomly generated graph
    populateRandom(nodes, edges);
      }
    }
  } else {                 // populate from file
    populateFromFile();
  }

  // To create empty graph to transpose our values into,
  // we need to clear out builder settings that would populate a new graph.
  savedBuilder.fileHandle = null;
  savedBuilder.nodes = 0;
  savedBuilder.edges = 0;

  // otherwise, everything the same, so just pass modified builder to constructor
  // save the reference to this graph ( ready for the reversal method to use )
  this.gPrime = new Graph(savedBuilder);

)

再来一次。目标是两个图对象,每个对象中的 gPrime 都引用另一个。

顺序是: build g - - - populate g - - - 将g反转为一个与g具有相同特征的空图

所以,这是我不太明白的问题。

如果我将 g 分配给 gPrime.gPrime,无论是在 g 我们构建之后的构建中还是在构造函数的底部,我都会收到一条错误消息,指出 gPrime 是最终的。 Eclipse 表示它是第一个有问题的 gPrime - - - 这是真的 - - 它是最终的并且已分配。但是 gPrime.gprime (重点放在第二个 gPrime 上)尚未分配。 (我搜索了整个程序。)

我还尝试将赋值放在 reverse 方法的底部。同样的事情。

我还在构建器中尝试了 g.gPrime.gPrime。同样的事情。

这几乎就像编译器对哪个 gPrime 正在接收分配感到困惑。

我确定有些东西我没有看到或理解 - - - 但 - - - 不知道如何实现。

如果我去掉 final,我就可以完成这项工作,但我正在努力做到不可变。

最佳答案

您需要不可变的循环依赖。您必须实现它,这样当您构建 A(在 A 的构造函数中)时,您必须使用 调用 Bconstructor >这个

这是构建器的代码(你必须确保整个构建过程不会从当前线程中逃逸):

public class A {

  private final B b_;
  private final String name_;

  private A(Builder b) {
    b_ = b.bB_.a(this).build();
    name_ = b.name_;
  }

  public String name() {
    return name_;
  }

  public B b() {
    return b_;
  }

  @Override
  public String toString() {
    return "[" + name_ + ": " + b_.name() + " ]";
  }

  public static class Builder {

    private B.Builder bB_;
    private String name_;

    public Builder bB(B.Builder bB) {
      bB_ = bB;
      return this;
    }

    public Builder name(String arg) {
      name_ = arg;
      return this;

    }

    public A build() {
      return new A(this);
    }
  }

}

B 类:

public class B {

  private final A a_;
  private final String name_;

  private B(Builder b) {
    a_ = b.a_;
    name_ = b.name_;
  }

  public String name() {
    return name_;
  }

  @Override
  public String toString() {
    return "[" + name_ + ": " + a_.name() + " ]";
  }

  public static class Builder {

    private A a_;
    private String name_;

    public Builder a(A a) {
      a_ = a;
      return this;

    }

    public Builder name(String arg) {
      name_ = arg;
      return this;

    }

    public B build() {
      return new B(this);
    }
  }

}

使用方法:

public class Main {

  public static void main(String[] args) {
    A.Builder aBl = new A.Builder().name("I am A1");
    B.Builder bBl = new B.Builder().name("I am B1");

    A a = aBl.bB(bBl).build();

    System.out.println(a);
    System.out.println(a.b());

  }

}

^
^
^
如果你想在循环依赖中有一个类和两个对象):

public class A {

  private final A other_;
  private final String name_;

  private A(Builder b) {
    if (b.otherBulder_ != null) {
      other_ = b.otherBulder_.otherInstance(this).build();
    } else {
      other_ = b.otherInstance_;
    }
    name_ = b.name_;
  }

  @Override
  public String toString() {
    return "[" + name_ + ": " + other_.name() + " ]";
  }

  public String name() {
    return name_;
  }

  public A other() {
    return other_;
  }

  static class Builder {

    private Builder otherBulder_;
    private A otherInstance_;
    private String name_;

    Builder name(String name) {
      name_ = name;
      return this;
    }

    Builder otherBuilder(Builder other) {
      otherBulder_ = other;
      return this;
    }

    Builder otherInstance(A instance) {
      otherInstance_ = instance;
      return this;
    }

    A build() {
      return new A(this);
    }
  }

  public static void main(String[] args) {
    Builder a1B = new Builder().name("A1");
    Builder a2B = new Builder().name("A2");

    A a = a1B.otherBuilder(a2B).build();
    System.out.println(a);
    System.out.println(a.other());

  }
}

关于java - build 者的最后障碍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6259502/

相关文章:

java - Apache POI - FileInputStream 工作,文件对象失败(NullPointerException)

Java,False && False 解决方法

javascript - 如何防御性地防止 Redux 状态的突变?

c# - 当方法采用对象 C# 时,字符串作为引用参数的问题

Python:创建后卡住字典键

使用生成器的 C# 构造对象

java - 使用 ListView 从另一个 Activity 打印 ArrayList

c++ - 使用内部结构构建器映射

c# - 使用 Builder 类通过 DI 重新创建子对象集?

java - 为什么我的 ArrayList 包含添加到列表中的最后一项的 N 个副本?