web-dev-qa-db-fra.com

Implémenter Mixin en Java?

Avec Java 6, comment puis-je implémenter un mixin ? C'est très facile et possible en Ruby. Comment puis-je me ressembler en Java?

53
Lennie

Vous pouvez utiliser CGLIB pour cela. La classe Mixin est capable de générer une classe dynamique à partir de plusieurs délégués/interfaces:

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) 
21
Daniel Fanjul

Je dirais simplement utiliser la composition d'objet. Chaque fois que vous souhaitez ajouter de nouvelles fonctionnalités, composez un autre objet dans la classe en tant que membre. Si vous souhaitez créer toutes vos classes mélangées du même type, vous pouvez utiliser un tableau en tant qu'objet membre, chaque élément étant composé avec tous les autres et vous pouvez envoyer un élément particulier.

13
Martin

Méthodes par défaut

Je sais que la question dit Java 6, mais dans Java 8, nous aurons une alternative décente: méthodes par défaut .

Nous pourrons ajouter des implémentations 'par défaut' des méthodes d'interface, afin de pouvoir ajouter de nouvelles méthodes sans interrompre chaque classe implémentant l'interface.

Tant que votre mixin n'a pas besoin d'état, vous pouvez écrire du code dans une interface. Ensuite, votre classe peut implémenter autant d’interfaces qu’elle le souhaite et bouge, vous avez des mixins .

Est-ce un abus du système? Un peu, mais cela n'entre pas dans les problèmes d'héritage multiple car il n'y a pas d'état.

Bien sûr, c’est aussi le principal inconvénient de cette approche.

13
Brad Cupit

Étant donné que Java ne prend en charge qu'un seul héritage, cela n'est pas possible. Regardez WP: Mixin .

EDIT: à cause des commentaires sur les interfaces: L'aspect intéressant de mixins est que vous pouvez les combiner sans écrire le code de la combinaison. Avec les interfaces, vous devez implémenter vous-même les fonctionnalités de la combinaison (sauf une classe que vous pouvez étendre)!

8
Johannes Weiss

L'approche la plus simple consiste à utiliser des importations statiques. Cela permet de réutiliser du code qui "ressemble" à une partie de la classe, mais qui est vraiment défini ailleurs.

Avantages:

  • vraiment facile
  • vous pouvez "mixer" autant d'importations statiques que vous le souhaitez

Les inconvénients:

  • les méthodes statiques n'auront pas accèsà 'ceci', vous devrez donc le transmettrein manuellement
  • no state: vos méthodes statiques ne peuvent pas avoir leurs propres champs d'instance. Ils peuvent uniquement définir leurs propres champs statiques, qui sont ensuite partagés par tout objet appelant la méthode statique.
  • ne peut pas définir de méthodes publiques sur la classe client (celle avec le code mélangé dans celle-ci). En Ruby, importer un mixin définira en fait ces méthodes publiques en tant que méthodes publiques sur votre classe. En Java, l'héritage serait une meilleure solution dans ce cas (en supposant que vous n'avez pas besoin d'étendre plusieurs classes)

Exemple:

import static my.package.MyHelperUtility.methodDefinedInAnotherClass;

public class MyNormalCode {
    public void example() {
        methodDefinedInAnotherClass();
    }
}
7
Brad Cupit

Dans la mesure où un mixage Ruby est l'équivalent d'une classe abstraite Java, non, vous ne pouvez pas implémenter un mixage en Java. Vous pouvez vous rapprocher en utilisant des interfaces et en définissant ainsi absolument aucun code dans votre mix-in, mais vous ne pouvez pas obtenir directement le même comportement que dans un mix en Ruby.

5
Eddie

MISE À JOUR: Qi4j est maintenant Apache Polygene, https://polygene.Apache.org

La définition de Mixin par Qi4j est probablement assez unique, car elle ne commence pas par une classe de base. En allant à l'extrême, un tout nouveau paradigme de la manière dont les applications sont construites émerge, et nous appelons cela la programmation orientée composite. Le composite est l'équivalent 'd'objet' et non seulement Mixins est câblé ensemble, mais également les contraintes (validation), les préoccupations (autour du conseil) et les effets secondaires (ne peuvent pas modifier le résultat de la méthode).

Je pense donc que Qi4j a une très forte histoire à raconter. Les mixins peuvent être «typés» ou «génériques», ils peuvent être publics (accessibles en dehors du composite) ou purement privés (au sein du composite). Qi4j définit fermement ce que sont les propriétés et a une persistance intégrée, ce qui ne fuit pas la mise en œuvre du stockage dans votre domaine (avertissement; Qi4j fuit sur votre domaine). Et une fois que les entités persistantes sont entrées dans l’image, une définition forte d’une association est également requise (et incluse dans Qi4j).

Voir http://www.qi4j.org/state-modeling.html pour un bon aperçu.

En Qi4j, SEUL les Mixins ont un état. Les contraintes/préoccupations/effets secondaires ne peuvent pas avoir d'état (s'ils ont besoin de faire référence à un mixin privé).

Pour définir un composite dans Qi4j, il est possible de le faire de manière structurelle sur les types eux-mêmes, OR au moment de l’amorçage lors de la création du modèle d’exécution.

Structurellement;

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

Au démarrage;

public interface Car
{}

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

Pourtant, cela ne fait que toucher à la surface des fonctionnalités de Qi4j.

5
Niclas Hedhman

Jetez un coup d’œil à http://code.google.com/p/javadude/wiki/AnnotationsMixinExample

Il utilise un ensemble d'annotations que j'ai créées.

Remarque: je travaille sur une mise à jour majeure des annotations, qui inclut des ruptures d'API. Je prévois de publier une nouvelle version dans les prochaines semaines.

4
Scott Stanchfield
4
Ray Tayek

Vous ne savez pas exactement quelles fonctionnalités de mixins vous recherchez, mais vous pouvez en grande partie utiliser le motif décoratif.

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

2
Lewis Diamond

Vous pouvez maintenant faire des mixins avec Java (c'est-à-dire 5,6,7) en utilisant AspectJ ITD . Bien entendu, Java 8 ajoutera de meilleures capacités avec ses méthodes defender.

2
Adam Gent
2
TofuBeer

Je crois ça peut répondre à votre question ... bien que je ne sois pas tout à fait bien sûr de comprendre ce qu'est un mixin ...

1
leeand00

J'explore de fournir ceci pour Java 7. Ma première étape consistera à utiliser l'exemple présenté dans cet article:

Il devrait fonctionner avec Java 6, il est similaire aux autres options d’injection ci-dessus. Sur la base de mon expérience avec Mixins en C # et Ruby, vous devriez viser à implémenter des mixins, pas seulement à les imiter ou à les simuler. 

Un autre modèle est celui utilisé avec Jackson :

Si vous pouvez utiliser la nouvelle version de Java 8, par exemple, si vous êtes en mode préliminaire, cela pourrait aider.

Utilisation de la méthode d'extension virtuelle, ce qui nécessite un effort de mixage 'be-a'. Donc, dans mon esprit, il est encore tôt et je préfère l’approche plus propre (ou similaire) proposée par le premier lien.

1
will

Oui, le moyen le plus simple et pratique d'implémenter l'approche mixins en Java - consiste à utiliser une importation statique à partir d'une classe contenant des méthodes statiques. 

1
SergeZ

Une réponse à une vieille question.

J'ai jeté un coup d'œil à Apache Zest. Peut-être que c'était juste moi, mais je trouve les exemples un peu lourds. Et je ne pouvais pas tout à fait comprendre le point. Une autre alternative peut être des équipes d'objet.

Mais je vous suggère de jeter un oeil à ce rapport:

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

Cela pourrait couvrir partiellement ce que vous voulez faire. Cela semble simple.

Voici un exemple:

Définir l'interface pour les rôles:

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

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

Définition du type rigide 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";
}
}

Définir le rôle de classe Bonobo ...

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

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

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

}

Définition du rôle de classe Portuguese ...

@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!";
}

}

Lancer le test ...

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

Imprimerait ...

"Hey there"
"Dance modified!"
0
skynetDude

Jetez un coup d’œil à mon petit projet de démonstration sur la création de mixins en Java pur avec cglib. Il s’agit principalement d’un appel à un générateur de proxy. C'est un allié. L'exemple contient un scénario de test Junit montrant comment instancier le proxy.

https://github.com/literadix/JavaMixins

0
Maciej A. Bednarz

Le terme 'Mixin' n'est-il pas équivalent au terme Java 'aspect' dans le mouvement de programmation orienté aspect? AspectJ vaut probablement le coup d'oeil.

0
LeeGee