57

使用 Java 6,如何实现mixin?这在 Ruby 中非常简单且可行。我怎样才能在 Java 中得到类似的东西?

4

17 回答 17

23

您可以为此使用CGLIBMixin类能够从多个接口/对象委托生成动态类:

static Mixin    create(java.lang.Class[] interfaces,
                        java.lang.Object[] delegates)
static Mixin    create(java.lang.Object[] delegates)
static Mixin    createBean(java.lang.Object[] beans) 
于 2009-02-26T18:36:33.163 回答
17

默认方法

我知道 Java 6 的问题,但在 Java 8 中我们将有一个相当不错的选择:默认方法

我们将能够添加接口方法的“默认”实现,因此我们可以添加新方法而不会破坏实现接口的每个类。

只要你的 mixin 不需要状态,你就可以在接口中编写代码。然后你的类可以实现任意数量的这些接口,并且繁荣,你有 mixins

这是滥用系统吗?一点点,但它不会涉及任何多重继承问题,因为没有状态。

当然,这也是这种方法最大的缺点。

于 2012-12-21T15:19:10.930 回答
14

我想说只使用对象组合。每次你想加入新功能时,将另一个对象作为成员组合到类中。如果你想让你的所有混合类都具有相同的类型,你可以使用一个数组作为成员对象,其中每个元素都由所有其他元素组成,并且你可以分派到一个特定的元素。

于 2009-02-25T23:16:06.727 回答
9

由于 Java 只支持单继承,这是不可能的。看看WP: Mixin

编辑:由于关于接口的评论:mixins 的酷之处在于您可以组合它们而无需编写组合代码。使用接口,您必须自己实现组合的功能(除了一个可以扩展的类)!

于 2009-02-25T19:37:26.737 回答
7

最简单的方法是使用静态导入。它允许代码重用“看起来”像是类的一部分,但实际上是在其他地方定义的。

优点:

  • 真的很容易
  • 您可以“混合”任意数量的静态导入

缺点:

  • 静态方法无法访问“this”,因此您必须手动传递它
  • 无状态:您的静态方法不能有自己的实例字段。他们只能定义自己的静态字段,然后由调用静态方法的任何对象共享。
  • 无法在客户端类上定义公共方法(其中混入了代码)。在 Ruby 中,导入 mixin 实际上会将这些公共方法定义为类上的公共方法。在 Java 中,在这种情况下继承会是更好的解决方案(假设您不需要扩展多个类)

例子:

import static my.package.MyHelperUtility.methodDefinedInAnotherClass;

public class MyNormalCode {
    public void example() {
        methodDefinedInAnotherClass();
    }
}
于 2009-08-12T16:39:23.730 回答
5

从某种意义上说,Ruby mix-in 等同于 Java 抽象类,不,您不能在 Java 中实现 mix-in。您可以通过使用接口来接近并因此在您的混入中绝对不定义任何代码,但是您不能直接实现与在 Ruby 混入中相同的行为。

于 2009-02-25T19:40:42.673 回答
5

更新:Qi4j 现在是 Apache Polygene,https ://polygene.apache.org

Qi4j 对 Mixins 的定义可能非常独特,因为它不是从基类开始的。通过走向这个极端,一个全新的应用程序构建范式出现了,我们称之为面向复合编程。Composite 是“对象”等价物,不仅将 Mixins 连接在一起,而且还有 Constraints(验证)、Concerns(围绕建议)和 SideEffects(不能改变方法结果)。

所以我认为 Qi4j 有一个非常强大的 Mixin 故事要讲。Mixin 可以是“类型化的”或“通用的”,它们可以是公共的(可在组合外访问)或纯私有的(在组合内)。Qi4j 强烈定义了属性是什么,并继续具有内置的持久性,它不会将存储实现泄漏到您的域中(警告;Qi4j 泄漏到您的域)。并且一旦持久实体进入图片,还需要对关联的强定义(并包含在 Qi4j 中)。

请参阅http://www.qi4j.org/state-modeling.html以获得良好的概述。

在 Qi4j 中,只有 Mixins 有状态。Constraints/Concerns/SideEffects 不能有状态(如果有的话,他们需要引用私有 mixin)。

要在 Qi4j 中定义组合,可以在类型本身的结构上进行,或者在创建运行时模型时在引导时进行。

结构上;

@Mixins({PetrolEngfineMixin.class, FourWheelsMixin.class})
public interface Car extends HasEngine, HasWheels, EntityComposite
{}

在启动时;

public interface Car
{}

public class CarModuleAssembler implements Assembler { public void assemble( ModuleAssembly module ) { module.entities( Car.class ) .withMixins( PetronEngineMixin.class, FourWheelsMixin.class ); } }

然而,这只是触及 Qi4j 中特征的表面。

于 2012-11-03T11:41:19.057 回答
4

看看http://code.google.com/p/javadude/wiki/AnnotationsMixinExample

它使用了我创建的一组注释。

注意:我正在对注释进行重大更新,其中包括一些 API 损坏。我计划在接下来的几周内发布一个新版本。

于 2009-02-25T21:52:50.483 回答
3

刚刚遇到:https ://blog.berniesumption.com/software/mixins-for-java/(Borken 链接已更新)

于 2009-08-17T00:08:18.233 回答
2

您现在可以使用 AspectJ ITDs 使用 Java(即 5、6、7)进行 Mixins。Java 8 当然会通过其防御方法添加更好的功能。

于 2013-02-01T16:07:44.027 回答
2

在 Java 中伪造 mixins:http: //jonaquino.blogspot.com/2005/07/java-mixin-pattern-or-faking-multiple.html

于 2009-02-25T19:39:45.390 回答
2

不确定您正在寻找 mixins 的哪些功能,但其中大部分功能都可以使用装饰器模式来完成。

http://en.wikipedia.org/wiki/Decorator_pattern#Java

于 2013-05-14T17:23:21.660 回答
1

我正在探索为 Java 7 提供此功能。我的第一个切入点是使用本文中显示的示例:

它应该适用于 java 6,它类似于上面的其他注入选项。根据我在 C# 和 Ruby 中使用 Mixins 的经验,您应该致力于实现 mixins,而不仅仅是模拟或伪造它。

另一种模型是与Jackson一起使用的模型:

如果您可以使用新的 Java 8 版本,比如说您处于预发布模式,那可能会有所帮助。

使用 Virtual Extension 方法,这需要努力 ' be-a ' mixin。所以在我看来,这还为时尚早,我更喜欢第一个链接提供的更简洁的方法(或类似方法)。

于 2014-05-28T23:03:16.987 回答
1

是的,在 Java 中实现 mixins 方法最简单、最方便的方法是从包含静态方法的某个类中使用静态导入。

于 2011-08-19T09:35:52.253 回答
0

在面向方面的编程运动中,术语“混合”不等同于 Java 术语“方面”吗?AspectJ 可能值得一看。

于 2012-01-13T09:25:41.593 回答
0

一个老问题的答案。

我看了看 Apache Zest。也许只有我一个人,但我发现这些例子有点麻烦。我不能完全理解这一点。另一种选择可能是对象团队。

但我建议你可以看看这个 repo:

https://github.com/Mashashi/javaroles/

它可能部分涵盖了您想要做的事情。看起来很简单。

这是一个例子:

定义角色的接口:

public interface Human {
String hello(); 
String die(String age);  
String eat();
String dance();
}

public interface Monkey {String hello(); String eat();}

定义刚性类型 AnimalRoles...

public class AnimalRoles implements Human, Monkey{

public static final String HALLO = "Default hallo";
public static final String DIE = "Default they kill me...";
public static final String EAT = "Default eat...";

@ObjectForRole public Human human;

@ObjectForRole public Monkey monkey;

public AnimalRoles(Human human, Monkey monkey){
    this.human = human;
    this.monkey = monkey;
    if(this.human!=null){
        ((Portuguese)this.human).core = this;
    }
}

@Override
public String hello() {
    return HALLO;
}

@Override
public String die(String age) {
    return DIE+age;
}

@Override
@TurnOffRole
public String eat() {
    return EAT;
}

@Override
public String dance() {
    return "Just dance";
}

public String notInRole(){
    return "Oh oh";
}
}

定义类角色 Bonobo...

public class Bonobo implements Monkey{
public Bonobo() {}

@Override
public String hello(){
    return "Ugauga";
}

@Override
public String eat() {
    return "Nhamnham";
}

}

定义阶级角色葡萄牙语...

@RoleObject(types = { AnimalRoles.class })
public class Portuguese implements Human{

public static final String HALLO = "Hey there";
public static final String DIE = "They killed me";
public static final String EAT = "Eating boiled pork now";

public AnimalRoles core;

public Portuguese() {}

@Override
public String hello() {
    return HALLO;
}

@Override
public String die(String age) {
    return DIE+age;
}

@Override
public String eat() {
    return EAT;
}

@Override
public String dance() {
    return core.dance()+" modified!";
}

}

运行测试...

new RoleRegisterComposition().registerRools();
AnimalRoles a = new AnimalRoles(new Portuguese(), new Bonobo());
System.out.println(a.hello());
System.out.println(a.dance());

会打印...

"Hey there"
"Dance modified!"
于 2016-02-09T18:36:09.573 回答
0

请看一下我的小型演示项目如何使用 cglib 在纯 java 中创建 mixins。主要它只是对代理生成器的调用。这是盟友。该示例包含一个 junit 测试用例,演示如何实例化代理。

https://github.com/literadix/JavaMixins

于 2016-02-29T09:55:56.897 回答