Groovy中的@Delegate,@Mixin和Traits之间的区别? [英] Difference between @Delegate, @Mixin and Traits in Groovy?

查看:212
本文介绍了Groovy中的@Delegate,@Mixin和Traits之间的区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人会说什么时候我想使用 Groovy Traits vs. Mixins(@Mixin)vs. Delegates(@Delegate)?也许一些取舍和设计问题将有所帮助。



他们似乎都允许重用多个类的行为。谢谢。 : - )



此SO线程也有帮助:

我同意,他们都似乎允许重复使用多个类的行为。然而,有分歧,而且
理解这些可能有助于您的决定。



在提供每个功能的简要摘要/亮点和合适的$ b的示例之前


结论/典型用法:





现在,我们来看看这些更多的细节。



@Delegate



在许多情况下使用。也就是说,它经常被不正确地使用。 Java中的经典示例是
扩展输入流,读者或收集类。对于大多数这些,使用继承与
紧密结合实现。也就是说,实际的实现被写成使得
公共方法之一实际上使用另一个。如果您同时覆盖,并且您调用 super ,那么您可能会收到不必要的
副作用。如果实现在更新版本中发生变化,那么您将不得不更新您的
的处理。



相反,您应该努力使用组合继承



示例,计数列表列出添加到列表中的元素:

  class CountingList&E {
int counter = 0
@Delegate LinkedList< E> list = new LinkedList<>()
boolean addAll(Collection<?extends E> c){
counter + = c.size()
list.addAll(c)
}
boolean addAll(int index,Collection<?extends E> c){
counter + = c.size()
list.addAll(index,c)
}
//更多添加具有计数器更新的方法
}

在此示例中, @Delegate 删除您所有公开方法的所有繁琐的锅炉版代码,您
想要原样离开,即添加简单转发的方法调用底层列表。另外,
CountingList 与实现分开,以便您不必关心这些
方法之一是否通过调用其他。在上面的例子中,实际上是这样,因为
LinkedList.add(Collection)调用 LinkedList.add(int,Collection) ,所以它不会像使用继承一样直接



总结:




  • 为委托对象中的所有公共方法提供默认实现。


    • 具有明确添加的相同签名的方法优先。



  • 您可以添加几个 @Delegate s一班


    • 但是如果你这样做,你应该考虑是否真的是可取的。

    • 钻石问题,即如果在具有相同签名的代表中有多种方法?


  • 上面示例中带有委托( CountingList )的类不是委托类的实例。


    • I.e。 CountingList 不是 LinkedList 的实例。


  • 用于避免通过继承紧密耦合。



@Mixin



由于即将到来的特征支持, @Mixin 转换将不适用于groovy 2.3。这提供了一个
提示,可以使用 @Mixin 可以执行的所有操作都可以改为使用traits。



根据我的经验, @Mixin 是一种混合的祝福。 :)



由核心开发人员承认,难以解决的错误是错误的。这不是说,这是
无用,远不是这样。但是,如果你有机会使用(或等待)groovy 2.3,那么你应该使用
traits。



AST转换是什么,只是简单将方法从一个类添加到另一个类。例如:

  class First {
String hello(String name){Hello $ name!
}

@Mixin(First)
class Second {
// more methods
}

assert new Second ().hello('Vahid')=='Hello Vahid!'

总结:




  • 将方法从一个类添加到另一个类。

  • 在groovy< 2.3中使用简单添加方法一个班到另一个


    • 不要添加到超级类(至少我有问题)


  • 错误的

  • 从groovy中弃用2.3

  • 隐式添加的方法是<

  • 将另一个类混合在一起的类不是另一个类的实例


    • 即可第二个不是的实例首先


  • 您可以将多个课程混合到另一个课程中



  • 用作一个简单的方法,将groovy中的一个类的功能添加到另一个<2.3



  • 运行时mixin



    运行时混合和 @Mixin 变换是完全不同的,他们解决不同的用例,并在完全不同的情况下使用
    。既然他们有相同的名字,很容易与另一个混淆,或者
    认为它们是一样的。但是,在groovy 2.3中,运行时混合是不会不被使用的。



    我倾向于考虑运行时混合作为向现有类添加方法的方法,如JDK中的任何类。
    这是Groovy为JDK添加额外方法所使用的机制。



    示例:

      class MyStringExtension {
    public static String hello(String self){
    returnHello $ self!
    }
    }

    String.mixin(MyStringExtension)

    assertVahid.hello()=='Hello Vahid!'

    Groovy还有一个很好的扩展模块功能,您不需要手动执行mixin,而是
    groovy只要找到该模块即可描述符在类路径中的正确位置。



    总结:




    • 添加方法任何现有课程


      • JDK中的任何课程

      • 任何第三方课程

      • 或任何你自己的课程


    • 覆盖任何具有相同签名的现有方法

    • 添加的方法不是在Java中可见

    • 通常用于扩展具有新功能的现有/第三方类



    特征



    T raits是新的groovy 2.3。



    我倾向于将这些特征视为熟悉的界面和类之间的东西。类似于轻量级
    类的东西。他们被称为接口与默认实现和状态在文档中。



    性状类似于 @Mixin 改造他们取而代之,但也更强大。对于初学者,他们
    的定义更为明确。特征不能直接实例化,就像一个接口,他们需要一个实现
    类。一个类可以实现许多特征。



    一个简单的例子:

      trait Name {
    abstract String name()
    String myNameIs(){我的名字是$ {name()}! }
    }
    trait年龄{
    int age(){42}
    }

    class Person implements Name,Age {
    String name (){'Vahid'}
    }

    def p = new Person()
    assert p.myNameIs()=='我的名字是Vahid!'
    assert p.age()== 42
    assert p instanceof Name
    assert p instanceof Age

    traits和@Mixin之间的直接区别是 trait 是一个语言关键字,而不是AST转换。
    此外,它可以包含需要由类实现的抽象方法。此外,一个类可以实现
    几个特征。实施特征的类是该特征的一个实例。



    总结:





    • 一个类可以实现多个特征。

    • 由特征实现的方法是

    • 兼容类型检查和静态编辑

    • 特征可以实现接口。

    • <
    • 一个特征可以扩展另一个特征。

    • 处理钻石问题是明确的。

    • 典型用法:


      • 添加类似的特征到不同的类。


        • (作为AOP的替代)


      • 组成一个



    Would someone explain when I would want to use Groovy Traits vs. Mixins (@Mixin) vs. Delegates (@Delegate)? Maybe some trade-offs and design concerns would help.

    They all seem to allow for reusing multiple "classes" of behavior. Thanks. :-)

    This SO thread was helpful too: Difference between @Delegate and @Mixin AST transformations in Groovy

    解决方案

    I agree, they all seem to allow reusing multiple "classes" of behaviour. There are differences, though, and understanding these will probably aid your decision.

    Before providing a brief summary/highlight of each feature and examples of suitable usage, let's just summarize on the conclusion of each.

    Conclusion / typical usage:

    • @Delegate: Used to add all the functionality of the delegate class, but still avoid tightly coupling to the actual implementation. Let's you achieve composition over inheritance.
    • @Mixin: Deprecated with groovy 2.3. Simple way to add methods from one or more classes into your class. Bug-ridden.
    • Runtime mixin: Add one or more methods into any existing class, e.g. a class in the JDK or a 3rd party library.
    • Traits: New in groovy 2.3. Well-defined way to add one or more traits to your class. Replaces @Mixin. The only one of these where added methods are visible in Java classes.

    And now, let's look into each of these with a little bit more detail.

    @Delegate

    Inheritance is over-used in many cases. That is, it is often improperly used. Classic examples in Java are extending input streams, readers or the collection classes.. For most of these, using inheritance is too tightly coupled with the implementation. That is, the actual implementation is written so that one of the public methods actually use another. If you override both, and you call super, then you might get unwanted side-effects. If the implementation changes in a later version, then you will have to update your handling of it as well.

    Instead, you should strive to use composition over inheritance.

    Example, a counting list that counts the elements added to a list:

    class CountingList<E> {
        int counter = 0
        @Delegate LinkedList<E> list = new LinkedList<>()
        boolean addAll(Collection<? extends E> c) {
            counter += c.size()
            list.addAll(c)
        }
        boolean addAll(int index, Collection<? extends E> c) {
            counter += c.size()
            list.addAll(index, c)
        }
        // more add methods with counter updates
    }
    

    In this example, the @Delegate removes all the tedious boiler-plate code for all public methods that you want to leave "as-is", i.e. methods are added that simply forwards the call to the underlying list. In addition, the CountingList is separated from the implementation so that you don't have to care whether one of these methods is implemented by calling the other. In the example above, that is actually the case, since LinkedList.add(Collection) calls LinkedList.add(int, Collection), so it would not be as straight-forward to implement using inheritance.

    Summary:

    • Provides default implementations for all public methods in the delegated object.
      • Methods with same signature that are explicitly added, take precedence.
    • Implicitly added methods are not visible in Java.
    • You can add several @Delegates to one class.
      • but if you do, you should consider whether that is really desirable.
      • what about the diamond problem, i.e. if you have multiple methods in the delegates with the same signature?
    • The class with delegates (CountingList in the example above) are not instances of the delegate class.
      • I.e. CountingList is not an instance of LinkedList.
    • Use to avoid tightly coupling through inheritance.

    @Mixin

    The @Mixin transform will be deprecated with groovy 2.3, due to the upcoming traits support. This provides a hint that everything that is possible to do with @Mixin, should be possible to do with traits instead.

    In my experience, @Mixin is sort of a mixed blessing. :)

    It is, by the core developers admission, bug-ridden with "hard-to-solve" bugs. That's not to say that it's been "useless", far from it. But if you have the opportunity to use (or wait for) groovy 2.3, then you should use traits instead.

    What the AST transform does, is simply to add the methods from one class into another. For instance:

    class First {
        String hello(String name) { "Hello $name!" }
    }
    
    @Mixin(First)
    class Second {
        // more methods
    }
    
    assert new Second().hello('Vahid') == 'Hello Vahid!'
    

    Summary:

    • Adds methods from one class into another.
    • Use in groovy <2.3 for simple addition of methods from one class to another
      • don't add to "super" classes (at least, I've had problems with that)
    • Bug-ridden
    • Deprecated from groovy 2.3
    • Implicitly added methods are not visible in Java.
    • The class that gets another class mixed in, are not instances of that other class
      • I.e. Second is not an instance of First
    • You can mix in several classes into one other class
      • what about the diamond problem, i.e. if you have methods in the mixed in classes with the same signature?
    • Use as a simple method of adding the functionality of one class into another in groovy <2.3

    Runtime mixin

    Runtime mixins and the @Mixin transform are quite different, they solve different use-cases and are used in totally different situations. Since they have the same name, it's easy to confuse one with the other, or to think that they are one and the same. Runtime mixins, however, are not deprecated in groovy 2.3.

    I tend to think about runtime mixins as the way to add methods to existing classes, such as any class in the JDK. It's the mechanism used by Groovy to add extra methods to the JDK.

    Example:

    class MyStringExtension {
        public static String hello(String self) {
            return "Hello $self!"
        }
    }
    
    String.mixin(MyStringExtension)
    
    assert "Vahid".hello() == 'Hello Vahid!'
    

    Groovy also have a nice extension module feature, where you don't need to manually perform the mixin, instead groovy does it for you as long as it finds the module descriptor in the correct location in the classpath.

    Summary:

    • Add methods to any existing class
      • any classes in the JDK
      • any 3rd party classes
      • or any of your own classes
    • Overrides any existing method with the same signature
    • Added methods are not visible in Java
    • Typically used to extend existing/3rd party classes with new functionality

    Traits

    Traits are new to groovy 2.3.

    I tend to view these traits as something between the familiar interface and class. Something akin to a "light-weight" class. They are dubbed "interfaces with default implementations and state" in the documentation.

    Traits are similar to the @Mixin transform that they replace, but they are also more powerful. For starters, they are much more well-defined. A trait cannot be instantiated directly, just like an interface, they need an implementing class. And a class may implement many traits.

    A simple example:

    trait Name {
        abstract String name()
        String myNameIs() { "My name is ${name()}!" }
    }
    trait Age {
        int age() { 42 }
    }
    
    class Person implements Name, Age {
        String name() { 'Vahid' }
    }
    
    def p = new Person()
    assert p.myNameIs() == 'My name is Vahid!'
    assert p.age() == 42
    assert p instanceof Name
    assert p instanceof Age
    

    The immediate difference between traits and @Mixin is that trait is a language keyword, not an AST transform. Further, it can contain abstract methods that needs to be implemented by the class. Further, a class can implement several traits. The class implementing a trait is an instance of that trait.

    Summary:

    • Traits provide an interface with implementation and state.
    • A class can implement multiple traits.
    • Methods implemented by a trait are visible in Java.
    • Compatible with type checking and static compilation.
    • Traits can implement interfaces.
    • Traits can not be instantiated by themselves.
    • A trait can extend another trait.
    • Handling of the diamond problem is well-defined.
    • Typical usage:
      • add similar traits to different classes.
        • (as an alternative to AOP)
      • compose a new class from several traits.

    这篇关于Groovy中的@Delegate,@Mixin和Traits之间的区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆