具有嵌套对象和构建器的不可变值对象

时间:2016-03-23 07:58:35

标签: d

我们有一个包含大量值对象的大型系统,这些对象目前被记录为不可变的,并且没有提供和改变对象的方法。在重写代码的某些部分时,我认为不仅要将类记录为不可变,而且将它们声明为不可变,这将是一个很好的练习。

具有嵌套对象的Value对象如下所示:

immutable class Nested
{
    int i;

    public this(int i) immutable
    {
        this.i = i;
    }
}

immutable class Value
{
    private Nested nested_;

    public immutable(Nested) nested() const
    {
        return this.nested_;
    }

    package this(immutable(Nested) nested)
    {
        this.nested_ = nested;
    }
}

每当需要对任何值进行更改时,我们使用构建器来创建副本并修改属性。到目前为止一切都很好 - 但是当谈到嵌套对象时,我遇到了麻烦。使用原始对象从构建器创建副本只能获取不可变嵌套对象并存储它。但是构建器如何将嵌套对象更改为新对象?

我从std.typecons想出了Rebindable - 但我不确定这是否是好习惯。

class Builder
{
    import std.typecons : Rebindable;

    Rebindable!(immutable(Nested)) nested_;

    this()
    {
        this.nested_ = null;
    }

    this(immutable(Value) value)
    {
        this.nested_ = value.nested;
    }

    public void nested(immutable(Nested) nested)
    {
        this.nested_ = nested;
    }

    public immutable(Value) value() const
    {
        return new immutable Value(this.nested_);
    }
}

void main()
{
    import std.stdio : writefln;

    immutable value = new immutable Value(new immutable Nested(1));

    writefln("i = %d", value.nested.i);

    auto builder = new Builder(value);
    immutable newNested = new immutable Nested(2);
    builder.nested = newNested;

    writefln("i = %d", builder.value.nested.i);
}

我是否在考虑不变性和常规正确性?

此致

鲁尼

1 个答案:

答案 0 :(得分:0)

您使用Rebindable的解决方案是可以的,我认为这是实现这一目标的最佳方式。另一个可能的解决方案是使嵌套_可变并使用强制转换,但这不是那么优雅和安全:

class Builder
{
    import std.typecons : Rebindable;
    union
    {
        private Nested m_nested_;
        immutable(Nested) nested_;
    }

    this()
    {
        this.nested_ = null;
    }

    this(immutable(Value) value)
    {
        this.nested_ = value.nested();
    }

    public void nested(immutable(Nested) nested)
    {
        this.m_nested_ = cast(Nested)nested;
    }

    public immutable(Value) value() const
    {
        return new immutable Value(this.nested_);
    }
}