有人会解释我何时想要使用Groovy Traits与Mixins(@Mixin)对阵代表(@Delegate)?也许一些权衡和设计问题会有所帮助。
他们似乎都允许重复使用多个"类"行为谢谢。 : - )
此SO主题也很有用:Difference between @Delegate and @Mixin AST transformations in Groovy
答案 0 :(得分:114)
我同意,他们似乎都允许重复使用多个"类"行为但是,有一些不同之处 了解这些可能有助于您的决定。
在提供每个功能的简要摘要/重点和适当的示例之前 用法,我们只是总结一下每个人的结论。
结论/典型用法:
现在,让我们更详细地研究每一个。
<强> @Delegate 强>
在许多情况下,继承被过度使用。也就是说,它经常被不正确地使用。 Java中的经典例子是
扩展输入流,读者或集合类。对于大多数这些,使用继承也是如此
与实施紧密结合。也就是说,实际的实现是这样编写的
公共方法实际上使用另一种如果您同时覆盖两者,并且您拨打super
,那么您可能会不受欢迎
副作用。如果实施在更高版本中更改,则您必须更新您的处理
它也是。
相反,您应该努力使用composition over inheritance。
示例,计算添加到列表中的元素的计数列表:
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
}
在此示例中,@Delegate
删除了您所有公共方法的所有繁琐的样板代码
想要离开&#34; as-is&#34;,即添加简单地将呼叫转发到基础列表的方法。此外,
CountingList
与实施分开,因此您无需关心其中一项
方法是通过调用另一个来实现的。在上面的例子中,实际情况就是这样,因为
LinkedList.add(Collection)
调用LinkedList.add(int, Collection)
,因此不会那么直截了当
实现继承。
要点:
@Delegate
添加到一个班级。
CountingList
)不是委托类的实例。
CountingList
不是LinkedList
。<强> @Mixin 强>
由于即将推出的特征支持,@Mixin
转换将被groovy 2.3弃用。这提供了一个
暗示可以用@Mixin
做的所有事情都应该与特征有关。
根据我的经验,@Mixin
是一种喜忧参半的祝福。 :)
由核心开发人员承认,错误地带着&#34;难以解决的问题&#34;错误。这并不是说它已经存在 &#34;无用&#34;,远离它。但如果您有机会使用(或等待)groovy 2.3,那么您应该使用 而不是特质。
AST转换的作用,只是将方法从一个类添加到另一个类。例如:
class First {
String hello(String name) { "Hello $name!" }
}
@Mixin(First)
class Second {
// more methods
}
assert new Second().hello('Vahid') == 'Hello Vahid!'
要点:
Second
不是First
运行时mixin
运行时mixins和@Mixin
转换完全不同,它们解决了不同的用例并被使用
在完全不同的情况下。由于它们具有相同的名称,因此很容易将一个与另一个混淆,或者与之相混淆
认为他们是同一个人。但是,运行时mixins在groovy 2.3中不推荐 。
我倾向于将运行时mixins视为向现有类添加方法的方法,例如JDK中的任何类。 它是Groovy用于向JDK添加额外方法的机制。
示例:
class MyStringExtension {
public static String hello(String self) {
return "Hello $self!"
}
}
String.mixin(MyStringExtension)
assert "Vahid".hello() == 'Hello Vahid!'
Groovy还有一个很好的extension module功能,你不需要手动执行mixin,而是 只要在类路径中的正确位置找到模块描述符,groovy就会为你做这件事。
要点:
<强>性状强>
特质是groovy 2.3的新功能。
我倾向于将这些特征视为熟悉的界面和类之间的东西。类似于轻盈的东西&#34; 类。它们被称为&#34;接口,默认实现和状态&#34;在文档中。
Traits与它们替换的@Mixin
变换类似,但它们也更强大。对于初学者来说,他们
更加明确。特征不能直接实例化,就像接口一样,它们需要实现
类。一个班级可以实现许多特征。
一个简单的例子:
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
traits和@Mixin之间的直接区别是trait
是一个语言关键字,而不是AST转换。
此外,它可以包含需要由类实现的抽象方法。此外,一个类可以实现
几个特点。实现特征的类是该特征的一个实例。
要点: