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?
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)
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.
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.
É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)!
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:
Les inconvénients:
Exemple:
import static my.package.MyHelperUtility.methodDefinedInAnotherClass;
public class MyNormalCode {
public void example() {
methodDefinedInAnotherClass();
}
}
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.
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.
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.
vient de traverser: http://www.berniecode.com/blog/2009/08/16/mixins-for-Java/
Vous ne savez pas exactement quelles fonctionnalités de mixins vous recherchez, mais vous pouvez en grande partie utiliser le motif décoratif.
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.
Fake mixins in Java: http://jonaquino.blogspot.com/2005/07/Java-mixin-pattern-or-faking-multiple.html
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 ...
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.
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.
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!"
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.
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.