2017-08-16 10 views
4

Ich habe eine Frage über OOP-Implementierung und Entwurfsmuster.Welches Designmuster wird verwendet (falls vorhanden)?

Ich habe ein festes Klassenmodell, das ich nicht ändern kann (weil es bei jedem Start der Anwendung automatisch generiert wird). Es gibt viele Klassen mit Gleichfeldern wie im folgenden Beispiel: Wie Sie sehen können, sind die Felder city und streets in beiden Klassen enthalten.

public class A{ 
    String city; 
    String street; 

    String name; 

    ....//get methods 
} 

public class B{ 
    String city; 
    String street; 

    String age; 

    ....//get methods 
} 

Ich brauche eine Adresse zu extrahieren, die beiden Arten von Klassen bilden und ich möchte es mit einem Verfahren implementieren (weil es zu sein scheint dumm zweimal den gleichen Code zu schreiben). Wenn das Klassenmodell veränderbar wäre, könnte ich eine neue Schnittstelle Addressable hinzufügen, die A und B implementieren könnte.

public interface Addressable{ 

    public String getStreet(); 
    public String getCity(); 
} 

//somewhere in code 
public Address getAddress(Addressable addressable){ 
     return new Address(addressable.getCity(), addressable.getStreet()); 
} 

Was ist der eleganteste Weg, das gleiche ohne Schnittstelle zu implementieren und ohne dasselbe für verschiedene Klassen zu programmieren?

+1

Es ist nicht klar, was Sie tatsächlich in A und B ändern können. – davidxxx

+0

Es gibt keine elegante Möglichkeit, Sie können einfach versuchen, in die entsprechende Klasse zu werfen, oder Reflexion (möglicherweise zu schwer für diese Notwendigkeit). –

+0

Wenn die Klassen nicht geändert werden können (wenn sie erzeugt werden, die zwar möglich sind) und Sie keine Wrapper/Decorators für die Klassen erzeugen können, die eine gemeinsame Schnittstelle implementieren, wäre die einzige andere Art, die ich sehen würde, eine Reflektion. Aber bevor ich auf diese Route gehe, denke ich darüber nach, was ohne Nachdenken getan werden könnte. Eine Möglichkeit, diese Wrapper zu generieren (oder zumindest zu füllen), könnte [mapsstruct] (http://mapstruct.org/) sein. – Thomas

Antwort

3

Wenn Sie nicht in der Lage sind, A oder B zu ändern, müssten Sie zwangsläufig eine verschlechterte Lösung haben.
Eine einfache und gut entworfene Lösung würde sich natürlich auf eine Schnittstelle verlassen, die eine Adressenabrufmethode (Address getAddress()) definiert, die A und B implementieren würde.

Sie könnten auch eine Wrapper-Klasse definieren:

public class WrapperA implements Addressable { 

    private final A a; 

    public WrapperA(A a) { 
    this.a = a; 
    } 

    @Override 
    public Address getAddress(){ 
    return new Address(a.getCity(), a.getStreet(), etc...); 
    } 

} 

Aber es kann sein, eher ungeschickt, wenn Sie diese Art Code für viele Klassen duplizieren.
Außerdem manipuliert der Client nicht mehr eine A, sondern eine WrapperA Klasse.
Es kann den tatsächlichen Client-Code brechen.
Also auch hier ist eine Schnittstelle erforderlich, wenn Sie einen echten Adapter implementieren möchten.

Wie gesagt, ohne Neugestaltung eines Minimums A oder B ist eine wirklich gute Lösung kompliziert.


Als Abhilfe können Sie eine Address Klasse definieren, die Factory-Methoden bietet Address von einem A oder einer B Instanz zu erstellen.

public class Address{ 

    ... 
    String city; 
    String street; 
    ... 

    private Address(){ 
    } 

    public static Address of(A a){ 
    return new Address(a.getStreet(), a.getCity(), ....); 
    } 

    public static Address of(B b){ 
    return new Address(b.getStreet(), b.getCity(), ...); 
    } 

} 

Dann verwenden Sie diese Methoden, um die Adresse auf die Nachfrage zu erstellen, wie Sie es brauchen.

0

Ich hatte eine ähnliche Situation, wo Klassen während des Build-Prozesses generiert werden. (In meinem Fall würde der Build-Prozess die Datenbank prüfen und eine Klasse pro Datenbanktabelle mit allen Feldern generieren.)

Sie geben an, dass die Klassen generiert werden, wenn Ihre Anwendung gestartet wird. Falls sie während des Erstellungsprozesses generiert werden, können Sie dem Build-Prozess ein zusätzliches Element hinzufügen, das die generierten Dateien ändert. In meinem Fall waren unsere Build-Server nur Linux, also fügte ich eine sed Zeile zu unserem ant Skript hinzu.

2

Sie könnten adapters schreiben, um eine gemeinsame Schnittstelle zur Verfügung zu stellen.

public class AdpaterA implements Addressable { 

    private final A a; 

    public AdapterA(A a) { 
    this.a = a; 
    } 

    @Override public String getStreet() { 
    return this.a.street; 
    } 

    // other method is omitted as homework ;-) 
} 

Dann würden Sie die Adapterklassen für die weitere Verarbeitung verwenden.

Verwandte Themen