TL;TR
L'histoire qu'il est pratique de faire une telle chose
Version de présentation.java
public class OneOf<A, B> {
final Optional<A> a;
final Optional<B> b;
public <C> C apply(Function<A, C> AtoC, Function<B, C> BtoC) {
if (a.isPresent()) {
return AtoC.apply(a.get());
} else {
return BtoC.apply(b.get());
}
}
}
Il y a des moments où vous souhaitez créer l'une des deux instances de classe différentes à partir d'une entrée. (Par exemple, lorsque vous souhaitez lire un fichier journal ou un formulaire dans lequel divers enregistrements sont agrégés et créer une instance distincte pour chaque contenu.) Vous pouvez également changer ces différentes instances en instances de classe unique pour l'agrégation finale. (Par exemple, lorsque vous souhaitez convertir le contenu d'une instance en SolrInputDocument afin de le plonger dans NoSQL.)
Par exemple, si vous souhaitez créer des instances de la classe SecondObjectA (journal d'accès) et de la classe SecondObjectB (journal des achats) à partir de la classe FirstObject (chaque ligne du fichier journal) et les convertir en classe FinalObject (SolrInputDocument), le code sera le suivant.
FirstObject firstObject = getFirstObject();
FinalObject finalObject;
if(firstObject.isTypeA()){
SecondObjectA secondObjectA = transformA(first);
finalObject = finalTransformA(secocndObjectA);
}else{
SecondObjectB secondObjectB = transformB(first);
finalObject = finalTransformB(secocndObjectB);
}
La meilleure solution consiste à modifier la conception de la classe afin que SecondObjectA et SecondObjectB aient une classe parent (ou une interface) commune SecondObject et SecondObject FirstObject.transform ().
FirstObject firstObject = getFirstObject();
SecondObject secondObject = firstObject.transform();
FinalObject finalObject = finalTransform(secondObject);
Cependant, ce n'est souvent pas le cas dans le monde. Dans de nombreux cas, la conception de la classe devient compliquée, elle ne peut pas être héritée en raison du problème du double héritage et la classe doit être utilisée. Cet article décrit les solutions de contournement possibles dans de tels cas.
Regardons le problème lorsque nous revenons au premier code.
Republier.java
FirstObject firstObject = getFirstObject();
FinalObject finalObject;
if(firstObject.isTypeA()){
SecondObjectA secondObjectA = transformA(first);
finalObject = finalTransformA(secocndObjectA);
}else{
SecondObjectB secondObjectB = transformB(first);
finalObject = finalTransformB(secocndObjectB);
}
Comme solution lorsque SecondObjectA et SecondObjectB n'ont pas d'interface commune ou de classe parent, vous pouvez trouver un moyen de créer un bean avec les deux instances.
public class MyBean {
private SecondObjectA secondObjectA;
private SecondObjectB secondObjectB;
//Ci-dessous getter/aligné avec setter
}
En faisant cela, la partie appelante peut être écrite comme si nous introduisions une classe parent commune. Mais
――NPE provient généralement d'un tel endroit (bien qu'il puisse être traité en le rendant immuable, en masquant le constructeur pour qu'il ait une valeur unique, etc.)
Et cela devient un foyer qui provoque un mauvais phénomène.
Si tu fais quelque chose comme ça
OneOf.java
public class OneOf<A, B> {
private final Optional<A> a;
private final Optional<B> b;
private OneOf(A a, B b) {
this.a = Optional.ofNullable(a);
this.b = Optional.ofNullable(b);
}
public static <A, B> OneOf<A, B> OneOfA(A a) {
return new OneOf<A, B>(a, null);
}
public static <A, B> OneOf<A, B> OneOfB(B b) {
return new OneOf<A, B>(null, b);
}
public Optional<A> getA() {
return a;
}
public Optional<B> getB() {
return b;
}
public boolean isA() {
return a.isPresent();
}
public boolean isB() {
return !isA();
}
public <C> C apply(Function<A, C> AtoC, Function<B, C> BtoC) {
if (isA()) {
return AtoC.apply(a.get());
} else {
return BtoC.apply(b.get());
}
}
public static <A, B, C> Function<OneOf<A, B>, C> totalize(Function<A, C> AtoC, Function<B, C> BtoC) {
return (one) -> one.apply(AtoC, BtoC);
}
}
Vous pouvez écrire comme ça.
Partie principale.java
FirstObject firstObject = getFirstObject();
OneOf<SecondObjectA,SecondObjectB> secondObject = transform(first);
FinalObject finalObject = secondObject.apply(this::finalTransformA,this::finalTransformB);
Alternativement, le premier objet peut être passé dans un flux. Dans ce cas
Partie principale.java
Stream<FirstObject> firstObject = getFirstObjectStream();
Stream<FinalObject> firstObject.map(this::transform).map(OneOf.totalize(this::finalTransformA,this::finalTransformB));
Comme ça.
Si vous introduisez la classe OneOf comme ceci, cela peut être simple et net. Puisqu'il peut être utilisé sans se soucier de la relation entre les classes, il peut également être utilisé pour les classes existantes, ce qui est souvent pratique. Cependant, si vous avez besoin de "l'une des deux classes homebrew", sachez que la conception de la classe peut ne pas être bonne. (Si vous l'utilisez efficacement même dans votre propre classe, ce sera efficace. Vocabulaire médiocre)
Recommended Posts