【问题标题】:Update immutable object without breaking immutability在不破坏不变性的情况下更新不可变对象
【发布时间】:2018-11-19 23:14:52
【问题描述】:

如何在不破坏不变性的情况下从另一个不可变对象获取更新的不可变对象。类似于在 Scala 中实现事物的方式或在 Immutables 库中实现事物的方式。

我怎样才能实现类似的目标 Customer.Builder.from(anotherCustomer).replaceOrder(oldOrder,newOrder).with(newName).build()

重用旧对象并将我想要的所有更改排队以构造新对象。

我正在使用 Java。

【问题讨论】:

  • 你不能,否则对象将不再是不可变的。不过,您可以创建修改后的副本。
  • 你的不可变对象是如何定义的?什么语言?给我们一些代码,我们可以给你一些建议。
  • 类似于纠正拼写错误的名称?序列化它,对 XML 说,做一些魔术,然后反序列化它。魔术可能是反序列化为可变形式,但更好地直接处理 XML 或序列化。

标签: java performance scala immutability immutable-collections


【解决方案1】:
public class Customer {
    private String name;    
    private Order order

    private Customer(CustomerBuilder builder) {
        this.name = builder.name;
        this.order = builder.order;
    }

    public Customer replace(Order order) {
        return new CustomerBuilder().name(this.name).order(order).build();
    }

    public static class CustomerBuilder {
        private String name;    
        private Order order

        public CustomerBuilder name(String name) {
            this.name = name;
            return this;
        }

        public CustomerBuilder order(Order order) {
            this.order = order;
            return this;
        }

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

【讨论】:

  • 这不是一个好的解决方案,因为每次更改我都需要构造一个新对象。在我说编辑之前,我更希望将命令排队,而不是一次执行所有更改,以便只构造 1 个新对象(除了更新的对象)。
  • 类似 Customer.Editor.name().order(editedOrder).addressRegistration(newAddress).edit();
  • 这正是你想要的,只有 build() 方法会触发实例化......这是一个简单的构建器模式,很常见,但是 replace 方法是一种满足你期望的自定义​​方法
【解决方案2】:

我推荐这本书涵盖该主题: https://www.amazon.ca/Effective-Java-Edition-Joshua-Bloch/dp/0321356683

我知道更新不可变对象的最佳方法是返回对象的修改副本,例如 java String

    String uppercase = "hello".toUpperCase()

我让流利的打字变得容易使用

    String uppercasewithoutletterL = "hello".toUpperCase().replace("L","")

【讨论】:

  • 您好,假设我有一个可以从另一个对象构建对象的生成器。然后我需要将所有我想要的更改排队。例如 Customer.Builder.from(anotherCustomer).replaceOrder(oldOrder,newOrder).build() 我该怎么做?
  • 我建议的不是构建器模式,而是返回修改后副本的“功能方法”,我的意思是 replaceOrder(old,new) 返回 Customer 对象的新实例。
【解决方案3】:

这里有一个小递归函数,它创建了一个更改后的不可变对象。它重新创建包含更改的每个嵌套对象。

const changeImmutable = (immutable: any, path: string[], newVal: any): any => {
  if(path.length) {
    let copy = Array.isArray(immutable) ? [...immutable] : {...immutable};
    copy[path[0]] = changeImmutable(copy[path[0]], path.slice(1), newVal);
    return copy;
  }
  return newVal; 
};

使用示例

let immutableObj = {a: {b: [{c: 'foo'}]}};

// change 'foo' to 'bar'
let newImmutableObj = changeImmutable(immutableObj, ['a', 'b', 0, 'c'], 'bar');

【讨论】:

    【解决方案4】:

    您可以在对象类型中实现Cloneable 接口。 另一种选择是为您的不可变对象提供构建器,该构建器可以从现有对象创建新实例。 those 之类的东西已经完成了......

    【讨论】:

      猜你喜欢
      • 2019-10-03
      • 2013-08-02
      • 1970-01-01
      • 2018-03-08
      • 1970-01-01
      • 2018-05-09
      • 2014-09-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多