2015-06-18 10 views
7

Ho un oggetto che ha alcuni array come campi. E 'di classe si presenta più o meno così:Metodo generalizzato per ottenere attributi di oggetto simili

public class Helper { 
    InsuranceInvoices[] insuranceInvoices; 
    InsuranceCollectiveInvoices[] insuranceCollectiveInvoices 
    BankInvoices[] bankInvoices; 
    BankCollectiveInvoices[] bankCollectiveInvoices; 
} 

Tutte le tipologie di fattura hanno un reciproco un'interfaccia marcatore fatture.
Ho bisogno di ottenere tutte le fatture per invocare un altro metodo su di esse.

Helper helperObject = new Helper(); 
// ... 

for (InsuranceInvoices invoice : helperObject.getInsuranceInvoices()) { 
    Integer customerId = invoice.getCustomerId(); 
    // ... 
} 
for (BankInvoices invoice : helperObject.getBankInvoices()) { 
    Integer customerId = invoice.getCustomerId(); 
    // ... 
} 

// repeat with all array fields 

Il problema è che tutte le fatture hanno solo l'interfaccia del marcatore in comune. Il metodo getCustomerID() non è definito da un'interfaccia o una classe reciproca. Questo è un comportamento che non posso cambiare a causa di una determinata specifica.

La ripetizione del codice all'interno di for-each-loop è qualcosa che mi infastidisce. Devo fare esattamente la stessa cosa su tutti gli oggetti di fattura nei quattro diversi array. Quindi quattro cicli for-each-loop che inutili gonfiano il codice.

Esiste un modo per scrivere un metodo generale (privato)? Un'idea era:

private void generalMethod(Invoice[] invoiceArray){ 
    // ... 
} 

Ma questo richiederebbe quattro controlli instanceof perché la classe Invoice non conosce il metodo getCusomterId(). Perciò non guadagnerei nulla; il metodo conterrebbe ancora le ripetizioni.

Sono grato per ogni possibile soluzione per generalizzare questo problema!

+1

modo, le classi tutte implementano 'Invoice', e tutti implementano' getCustomerId', ma ' getCustomerId' non è nell'interfaccia 'Invoice'? Dovrai usare reflection per accedere al metodo per nome e invocarlo. A questo punto, l'interfaccia 'Invoice' è abbastanza inutile. – njzk2

+0

Do 'getInsuranceInvoices',' getBankInvoices' ... tutti e quattro restituiscono lo stesso numero di fatture? – Rajesh

+3

Ho un suggerimento ... applicare un cluebat alla persona che ha fatto dell'interfaccia 'Fattura' un'interfaccia marcatore invece di una che specifica quali metodi hanno le fatture in comune. – Powerlord

risposta

7

Possibili soluzioni per generalizzare il problema (ordinato dal migliore al peggiore):

Utilizzando classe wrapper

public class InvoiceWrapper { 
    private String customerID; 
    public String getCustomerID() { 
     return customerID; 
    } 
    public InvoiceWrapper(BankInvoices invoice) { 
     this.customerID = invoice.getCustomerID(); 
    } 
    public InvoiceWrapper(InsuranceInvoices invoice) { 
     this.customerID = invoice.getCustomerID(); 
    } 
    // other constructors 
} 

Upd Se ho capito bene, è necessario fare qualcosa con ID in tutti gli array.Per utilizzare InvoiceWrapper, è necessario implementare iteratore nella classe Helper, che passerà attraverso gli array e restituirà un wrapper per ogni voce. Quindi, avrai codice che funziona con 4 array in ogni caso.

Utilizzando istanza di calchi

public class CustomerIdHelper { 
    public static String getID(Invoice invoice) { 
     if (invoice instanceof InsuranceInvoices) { 
      return ((InsuranceInvoices) invoices).getCustomerID(); 
     } else if ... 
    } 
} 

chiamando i metodi per nome tramite Riflessione

public class CustomerIdHelper { 
    public static String getID(Invoice invoice) { 
     Method method = invoice.getClass().getDeclaredMethod("getCustomerId"); 
     return (String) method.invoke(invoice); 
    } 
} 
+0

Grazie per i tuoi suggerimenti! Il primo approccio è qualcosa che non ho preso in considerazione. Ma potresti spiegarmi perché hai scelto l'approccio di Reflection come il peggiore dei tre? – DeMo

+1

@DeMo Ecco perché se qualcuno rimuove il metodo, non lo noterai. Nelle prime due varianti vedrai un errore di compilazione. – AdamSkywalker

2

Non è bello, ma si potrebbe uso di riflessione per cercare il getCustomerIdMethod e poi invoke() esso, cf. Class.getDeclaredMethod().

private void generalMethod(Invoice[] invoiceArray){ 
    try { 
    for (Invoice invoice : invoiceArray) { 
     Method getCustomerId = invoice.getClass().getDeclaredMethod("getCustomerId"); 
     getCustomerId.invoke(invoice); 
    } 
    } catch (Exception e) { 
    // ... 
    } 
} 

Do atto che questo è testato.

2

Se non è consentito modificare le classi gestite aggiungendo un'interfaccia personalizzata. La cosa migliore che puoi fare è avvolgerli con una classe personalizzata che ha le proprietà desiderate.

In questo modo avrai una classe con codice "non così bello" che converte le classi che non puoi toccare in classi piacevoli che corrispondono a un design corretto e utile.

Ad esempio è possibile avere una classe WrappedInsuranceInvoice che si estende WrappedInsurace e contiene un campo membro InsuranceInvoice. Se non hai bisogno di mantenere la lezione originale, potresti essere ancora migliore copiando i dati. In questo modo, ad esempio, potresti perdere gli array e utilizzare gli elenchi.

Problemi correlati