2014-09-23 2 views
6

Ich habe mehr verschiedene POJOs, die ein builder pattern verwenden, aber nach einem Builder für jede Zugabe und zum Erzeugen von Object.toString, Object.hashCode und Object.equals, meine Klassen rund 100 Zeilen Code am Ende werden. Es muss einen besseren Weg geben, damit umzugehen. Ich denke, dass eine Art reflektierender Erbauer viel helfen würde, aber ich bin mir nicht sicher, ob das eine gute Übung wäre und ich bin mir auch nicht sicher, wie ich das genau umsetzen würde. Mit anderen Worten, gibt es eine Möglichkeit, einen Builder wie diesen zu implementieren?Zu viel Vortex, wie kann ich meine POJO-Builder reduzieren?

Eine einfache POJO:

public class Foo { 

    public int id; 
    public String title; 
    public boolean change; 
    ... 

} 

Dann eine Art reflektierende Bauer:

Foo = ReflectiveBuilder.from(Foo.class).id(1).title("title").change(false).build(); 
+0

Verwenden Sie Apache commons für toString hashCode und gleich? Es ist immer noch ein Schmerz, aber sparen Sie eine Menge Zeit. Sie Code haben eine Basisklasse, die reflectively toString, equals und hashCode dann alle Ihre POJOs aus diesem – Leon

+0

@Leon ich tatsächlich ableiten. Aber jede Klasse wird immer noch 70-100 Codezeilen von jedem Builder haben.Es muss ein besseres Muster geben, das mir nicht bewusst ist, oder ein Weg, einen reflektierenden Baumeister zu implementieren, zumindest fühle ich mich so. – buildpattern

Antwort

4

Kurze Antwort keine. Was du verlangst, ist nicht möglich. Reflection betrachtet den Code zur Laufzeit und ruft Methoden dynamisch auf, er kann keine tatsächlichen Methoden generieren.

Was könnten Sie wären tun:

Foo foo = ReflectiveBuilder.from(Foo.class). 
       set("id", 1). 
       set("title", "title"). 
       build(); 

Dies hat drei massive Probleme:

  1. die Felder sind String s - ein Tippfehler verursacht einen Laufzeitfehler eher als eine Kompilierung einer ,
  2. Die Werte sind Object s - der falsche Typ verursacht einen Laufzeitfehler statt einer Kompilierzeit eins und
  3. wäre es viel langsamer als die Alternative, da Reflection sehr langsam ist.

So eine Reflektion basierte Lösung, während möglich (siehe Apache Commons BeanUtils BeanMap) ist überhaupt nicht praktisch.

Lange Antwort, wenn Sie bereit sind, einige Kompilierzeit Magie erlauben, können Sie Project Lombok verwenden. Die Idee hinter Lombok ist die Generierung von Codebausteinen aus Annotationen mit dem Java Annotation Preprocessor System.Die wirklich magische Sache ist, dass alle IDEs, auch die großen 3 zumindest, die Annotation-Vorverarbeitung und die Code-Vervollständigung funktionieren, auch wenn der Code nicht existiert wirklich.

Im Fall eines POJO mit einem Builder Sie @Data und @Builder

@Data 
@Builder 
public class Foo { 

    public int id; 
    public String title; 
    public boolean change; 
    ... 

} 

Die @Data Annotation erzeugen können:

  • ein erforderliches Argument Konstruktor (das trifft alle final Felder),
  • equals und hashCode Methoden, die alle Felder verwenden (kann mit der @EqualsAndHashCode Annotation)
  • ein toString Verfahren auf allen Gebieten konfiguriert werden (mit der Anmerkung und @ToString
  • public Getter und Setter für alle Felder konfiguriert werden (unter Verwendung der @Getter/@Setter Annotationen auf Feldern konfiguriert werden).

Die @Builder Anmerkung wird eine innere Klasse erzeugt Builder genannt, die unter Verwendung von Foo.builder() instanziiert werden kann.

Sie sicherstellen, dass Sie konfigurieren die equals, hashCode und toString Methoden, als ob Sie zwei Klassen mit Lombok haben, die Verweise auf einander haben, dann werden Sie mit einer Endlosschleife im Standardfall am Ende, da beide Klassen die anderen sind in diese Methoden.

Es gibt auch eine neue configuration system, die Sie zum Beispiel fließend Setter verwenden können, so dass Sie mehr oder weniger mit dem Erbauer zu tun, weg, wenn Ihr POJO wandelbar ist:

new Foo().setId(3).setTitle("title)... 

Für einen anderen Ansatz können Sie Schauen Sie sich Aspect-oriented programming (AOP) und AspectJ an. AOP erlaubt es Ihnen, Ihre Klassen in "Aspekte" zu zerlegen und sie dann unter Verwendung bestimmter Regeln unter Verwendung eines Pre-Compilers zusammen zu kleben. Zum Beispiel könnten Sie genau das umsetzen, was Lombok tut, indem Sie benutzerdefinierte Anmerkungen und einen Aspekt verwenden. Dies ist jedoch ein ziemlich fortgeschrittenes Thema und könnte durchaus übertrieben sein.

+0

Ich erkannte, dass 'Gson' tatsächlich einen sehr ähnlichen Ansatz verwendet, um ein' Objekt' zu deserialisieren, indem es Reflektion verwendet, um jedes 'Feld' zu initialisieren. Ein Builder, der auf der gleichen Reflektionsimplementierung basiert, ist vielleicht keine so schlechte Idee. Was denken Sie? – buildpattern

+1

@buildpattern Es ist eine schreckliche Idee, wie ich darauf hinweise. GSON macht das, weil es so ist. Sie verlieren die Sicherheit der Kompilierzeit, dh Sie können jederzeit Laufzeitfehler erleiden, und Sie verlieren an Geschwindigkeit. Verwenden Sie keine Reflektion, es sei denn, Sie ** absolut ** müssen und ** nie **, um das Standardprotokoll zu reduzieren. –

4

Vielleicht Project Lombok (ja die Website ist hässlich) ist eine Option für Sie. Lombok fügt Code basierend auf Anmerkungen in Ihre Klassen ein.

Mit Lombok verwenden Sie die @Data Annotationen erzeugt Getter, Setter, toString(), hashCode() und equals():

@Data 
public class Foo { 
    public int id; 
    public String title; 
    public boolean change; 
} 

Werfen Sie einen Blick auf das Beispiel auf dem @Data documentation section den generierten Code zu sehen.

Lombok bietet auch eine @Builder, die einen Builder für Ihre Klasse generiert. Aber beachten Sie, dass es sich um eine experimentelle Funktion:

@Builder 
public class Foo { 
    public int id; 
    public String title; 
    public boolean change; 
} 

Jetzt können Sie tun:

Foo foo = Foo.builder() 
    .id(123) 
    .title("some title") 
    .change(true) 
    .build(); 
0

Ich habe eine kleine Bibliothek CakeMold erstellt, um die POJOs flüssig zu initialisieren. Es verwendet Reflexion, was sicherlich nicht schnell ist. Aber kann sehr hilfreich sein, wenn Sie Tests schreiben müssen.

Person person = CakeMold.of(Person.class) 
    .set("firstName", "Bob") 
    .set("lastName", "SquarePants") 
    .set("email", "[email protected]") 
    .set("age", 22) 
    .cook(); 
1

Ich persönlich benutze this Website alle Code, um den vorformulierten für mich für die POJOs zu erstellen. Alles, was Sie tun müssen, ist das Einfügen der JSON, die Sie analysieren möchten, und es werden alle Klassen für Sie generiert. Dann benutze ich einfach Retrofit, um die Anfragen/Caching/Parsing der Informationen zu machen. Here ist ein Beispiel für Retrofit und POJOs in meinem Github-Konto. Ich hoffe es hilft!

Verwandte Themen