使用接口构造函数参数类型使类不可变

时间:2019-01-27 16:30:07

标签: java

我在业余时间自学计算机科学,目前正在参加伯克利的CS61B课程,该课程在线发布了材料。我本人已经能够弄清大部分事情,但在作业上却只停留在一点上。规范在这里:https://sp18.datastructur.es/materials/hw/hw4/hw4

挑战在于Solver类应该是不可变的。 Solver类具有以下API:

public class Solver {
    public Solver(WorldState initial)
    public int moves()
    public Iterable<WorldState> solution()
}

WorldState是一个接口,而不是一个类,如下所示:

package hw4.puzzle;

public interface WorldState {
    /** Provides an estimate of the number of moves to reach the goal.
     * Must be less than or equal to the correct distance. */
    int estimatedDistanceToGoal();

    /** Provides an iterable of all the neighbors of this WorldState. */
    Iterable<WorldState> neighbors();

    /** Estimates the distance to the goal. Must be less than or equal
     *  to the actual (and unknown) distance. */
    default public boolean isGoal() {
      return estimatedDistanceToGoal() == 0;
    }
}

因此,我无法将参数复制到规划求解构造函数。如果程序使用初始的WorldState调用求解器,然后更改该WorldState,则Solver解决方案也将反映该更改,因为它拥有对传入对象的引用。我能够通过专门设计Solver来解决此问题。将包中WorldState的实现作为参数,以便他们可以创建该类型的新对象并将参数复制到该对象。但是该分配应该在Solver类中保持通用性。

我试图做的一件事是创建一个WolrdState实现,作为Solver的子类,该继承器将int EstimatedDistanceToGoal和Iterable邻居变量作为参数,然后接口方法的实现将直接返回这些值。但是,我没有使它起作用,因为分配的其他部分将WorldState对象重铸为作为初始arg传入的特定实现(Board),并在此处中断。这也将是一大笔开销。

还有其他任何想法或方法可以指引我正确的方向吗?我知道该课程旨在合理地防止解决方案在线泄漏,因此,也许PM响应会更合适,或者只是提示而不是解决方案。谢谢您的帮助!

2 个答案:

答案 0 :(得分:0)

WorldState实现也应该是不变的。作业将告诉您创建一个名为Board的不变类,该类实现WorldState。

如果不是这种情况,您仍然可以通过克隆传递给构造函数的参数WorldState来使Solver不可变,并声明将其存储为final和private的属性。

请记住,如果您希望对象的状态不变,则不能对其进行更改,但是可以构造一个具有所需更改的新对象。 example文档很好地说明了可变类和不可变类之间的差异,而功能上基本上没有差异。

答案 1 :(得分:0)

  

不可变的类意味着一旦创建了对象,我们将无法更改   其内容。

我可以看到,WorldState实现是不可变的,因为它仅包含getter或计算。因此,您只需要将此引用保存到

public final class Solver {
    private final WorldState initial;

    public Solver(WorldState initial) {
        this.initial = initial;
    }

    public int moves() {
        // should not modify internal state; only calculation
    }

    public Iterable<WorldState> solution() {
        // should not modify internal state; only calculation
    }
}

最后,如果Solver类不更改其状态和所有变量的状态,例如initial,则可以将其视为不可变的。