Java中mixin的一个例子?

24
在《Effective Java》的第93-4页上,我遇到了术语“mixin”。但是我发现很难想象出mixin实际上是什么。请问有人可以通过在Java中提供mixin的示例来帮助我吗?

"mix-in"并不只有一个意思。如果您提供了书中的引用,那么帮助就会更容易些。 - Alexey Romanov
3个回答

27
您在提到Effective Java的第18项-优先使用接口而不是抽象类,我认为特别是以下部分:
接口非常适合定义mixin。松散地说,mixin是一种类型,类可以实现它以外加其“主要类型”,以声明它提供了一些可选行为。例如,Comparable是一个mixin接口,允许类声明其实例与其他可相互比较的对象有序。这样的接口之所以称为mixin,是因为它允许将可选功能“混合”到类型的主要功能中。抽象类不能用于定义mixin,原因与不能将其后期添加到现有类中相同:类不能有多个父类,并且在类层次结构中没有合理的位置来插入mixin。

本质上,抽象类和接口中指定功能的主要区别之一在于,接口版本可以在许多不同的类层次结构中使用,而抽象类只能在一个类层次结构树中使用,因为Java只允许单继承。


2
将此定义与其他语言(如Ruby或Python)中的mixin进行比较是有用的。在这些语言中,类可以有多个父类,因此一个类可以从任意数量的通用父类中引入逻辑。它们被认为是mixins,因为它们不被视为类的主要父类,而是一些已经“混合”的附加逻辑。示例:http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_modules.html#S2 - Brandon Yarbrough
19
接口不是混合类。接口不持有状态,甚至不持有代码,因此它不是混合类。例如,您不能定义一个名为 Traversable 的混合类,其中包含一个抽象方法 forEach 和10个基于它提供功能的具体方法(如 droptakefiltermap 等等)。使用接口,您可以声明所有这些方法,但实现此接口的任何类都必须为所有方法提供实现,而不仅仅是其中一个。抽象类在这方面非常适用,但它们只能作为类的一个父类,并将您置于特定的继承层次结构中,而不是混合类。 - RokL
1
@RokL 我认为这条评论是在Java 8发布之前的,之后您可以使用默认方法来实现“完全”相同的效果了吧? ;) - Haakon Løtveit
@HaakonLøtveit 不可以,你在接口中的默认方法只能操作参数,你仍然不能通过接口向对象添加字段,这就是例如 Scala 中混入类的作用。 - RokL
1
@RokL 但我们正在谈论Effective Java,以及在那里使用该单词的含义。你确实可以使用默认接口来做这样的事情。您可以轻松编写一个具有默认字符串toJson()的接口,其功能与您预期的完全相同。 - Haakon Løtveit

11

在Java中,不存在Mix-in的概念,因为没有办法将一段代码添加到不同层次结构的类中。要实现这一点,需要多重继承或至少使用Scala类型特质。


1
切面不是Java语言的一部分。在Java中,切面是通过字节码编织实现的,即在代码编译后进行的,因此它是一种编译后工具。 - RokL
但是Java可以实现这种字节码织入。接口代理是Java的一部分。 - Web Devie
1
接口代理不提供完整的混入支持。 - RokL

4
在《Effective Java》的范围内,它只是逻辑上的提及,并没有具体的Java实现。例如,Comparable接口。它不会改变你的类目的或者让你的API用户感到困惑。它只是混合了排序和比较的功能。因此,在Java语境中,我会将其缩小为装饰器模式。
另一种混入的变体可能是以下情况。假设你有:
interface IMyInterface
{
    public void doStuff();
}

class MyClass implements IMyInterface
{
    public void doStuff(){};
}

现在我们想要“混入”一些额外的功能。我们添加一个抽象类:
abstract class AbstractMixInProvider
{
    public abstract void doMixinStuff();
}

我们从AbstractMixInProvider扩展了MyClass:

class MyClass extends AbstractMixInProvider implements IMyInterface
{
    public void doStuff(){};
    public void doMixinStuff();
}

但是,正如我之前提到的那样,试图将mix-in概念引入Java看起来很丑陋,因为这只是在玩文字游戏。


这个例子仅适用于一个接口,没有混合。 - Web Devie
在这个例子中,我使用了AbstractMixInProvider作为mixin。它是否是接口并不重要。我试图描述一个@blackpanther能够理解'Effective Java'方法的示例情况。 - Michael Cheremuhin
用这种方法无法使用两个抽象类完成此操作。 - Web Devie
不,你不能。这就是为什么你可以为你的目标类使用多个接口或者一个包含多个接口的抽象Mixin提供者。这就是我认为称所有这些东西为“mixin”很奇怪的原因。 - Michael Cheremuhin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接