Groovy   发布时间:2022-04-12  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了Groovy:有没有比copyWith方法更好的处理@Immutable对象的方法大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在寻找一种灵活的方式来“修改”(复制一些值已更改)groovy中的不可变对象.有一个copyWith方法,但它只允许您替换对象的某些属性.它似乎不够方便.

假设我们有一组表示某个系统的域设计的类:

@Immutable(copyWith = truE)
class Delivery {
    @R_262_10495@ng id
    Person recipient
    List<Item> items
}

@Immutable(copyWith = truE)
class Person {
    @R_262_10495@ng name
    Address address
}

@Immutable(copyWith = truE)
class Address {
    @R_262_10495@ng street
    @R_262_10495@ng postalCode
}

我们假设我需要改变送货接收者的街道.在常规可变对象的情况下,执行:

delivery.recipient.address.street = newStreet

或者(在某些情况下可能有用):

delivery.with {recipient.address.street = newStreet}

当谈到对不可变对象做同样的事情时,根据我的知识,最好的方法是:

def recipient = delivery.recipient
def address = recipient.address
delivery.copyWith(recipient:
                      recipient.copyWith(address:
                                             address.copyWith(street: newStreet)))

它实际上是Spock集成测试代码所需要的,因此可读性和表现力很重要.上面的版本不能“动态”使用,所以为了避免创建大量的辅助方法,我已经实现了我自己的copyOn(因为copyWith被采用)方法,这使得它可以编写:

def deliveryWithNewStreet = delivery.copyOn {it.recipient.address.street = newStreet}

我想知道是否有最终的解决方案,存在于groovy或由一些外部库提供.谢谢

解决方法

为了完整起见,我提供了copyOn方法的实现.它如下:

class CopyingDelegate {
    static <T> T copyOn(T source,Closure closurE) {
        def copyingProxy = new CopyingProxy(sourcE)
        closure.call(copyingProxy)
        return (T) copyingProxy.result
    }
}

class CopyingProxy {
    private Object nextToCopy
    private Object result
    private Closure copyingClosure

    private final Closure simplyCopy = { instance,property,value -> instance.copyWith(createMap(property,value)) }
    private final def createMap = { property,value -> def map = [:]; map.put(property,value); map }

    CopyingProxy(Object nextToCopy) {
        this.nextToCopy = nextToCopy
        copyingClosure = simplyCopy
    }

    def propertymissing(@R_262_10495@ng propertyName) {
        def partialCopy = copyingClosure.curry(nextToCopy,propertyName)
        copyingClosure = { object,value ->
            partialCopy(object.copyWith(createMap(property,value)))
        }
        nextToCopy = nextToCopy.getProperties()[propertyName]
        return this
    }

    void setProperty(@R_262_10495@ng property,Object value) {
        result = copyingClosure.call(nextToCopy,value)
        reset()
    }

    private void reset() {
        nextToCopy = result
        copyingClosure = simplyCopy
    }
}

这只是在Delivery类中添加委托方法的问题:

Delivery copyOn(Closure closurE) {
    CopyingDelegate.copyOn(this,closurE)
}

高级解释:

首先,需要注意以下代码:delivery.recipient.address.street = newStreet被解释为:

>访问交付对象的收件人属性
>访问上述结果的地址
>使用NewStreet的值分配属性street

当然,CopyingProxy类没有任何属性,因此将涉及propertymissing方法.

因此,您可以看到它是一个propertymissing方法调用链,通过运行setProperty终止.

基本情况

为了实现所需的功能,我们保留了两个字段:nextToCopy(在开头交付)和ReplicationClosure(使用@Immutable(copyWith = truE)转换提供的copyWith方法初始化为简单副本).

此时,如果我们有一个像delivery.copyOn {it.id =’123′}这样的简单代码,那么根据simplyCopy和setProperty实现它将被评估为delivery.copyWith [id:’123′].

递归步骤

现在让我们看看如何使用更多级别的复制:delivery.copyOn {it.recipient.name =’newName’}.

首先,我们将在创建CopyingProxy对象时设置nextToCopy和copyingClosure的初始值,方法与上一个示例相同.

现在让我们分析在第一次propertymissing(@R_262_10495@ng propertyName)调用期间会发生什么.因此,我们将在curried函数 – partialCopy中捕获当前的nextToCopy(传递对象),ReplicationClosure(基于copyWith的简单复制)和propertyName(收件人).

然后这个复制将被合并到一个闭包中

{ object,value -> partialCopy(object.copyWith(createMap(property,value))) }

这成为我们新的复制关闭.在下一步中,将以Base Case部分中描述的方式调用ReplicationClojure.

结论

然后我们执行:delivery.recipient.copyWith [name:’newName’].然后将partialCopy应用于给我们delivery.copyWith [recipient:delivery.recipient.copyWith(name:’newName’)]的结果

所以它基本上是一个copyWith方法调用树.

最重要的是,您可以看到一些摆弄结果字段和重置功能.需要在一个闭包中支持多个作业:

delivery.copyOn { 
    it.recipient.address.street = newStreet
    it.id = 'newId' 
}

大佬总结

以上是大佬教程为你收集整理的Groovy:有没有比copyWith方法更好的处理@Immutable对象的方法全部内容,希望文章能够帮你解决Groovy:有没有比copyWith方法更好的处理@Immutable对象的方法所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。