2015-06-18 6 views
7

У меня есть объект с несколькими массивами в виде полей. Это класс примерно выглядит следующим образом:Обобщенный метод получения аналогичных атрибутов объекта

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

Всех типов счетов имеет обоюдный интерфейс маркеров счетов-фактур.
Мне нужно, чтобы все счета-фактуры вызывали на них другой метод.

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 

Проблема в том, что все счета-фактуры имеют только общий интерфейс маркера. Метод getCustomerID() не определяется взаимным интерфейсом или классом. Это поведение, которое я не могу изменить из-за данной спецификации.

Повторение кода внутри цикла for-each-это то, что меня беспокоит. Я должен делать то же самое на всех объектах счета в четырех разных массивах. Следовательно, четыре для каждой петли, которые не требуют раздувания кода.

Есть ли способ, которым я могу написать общий (частный) метод? Одна идея была:

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

Но для этого потребуется четыре InstanceOf проверки, потому что класс Счет не знает метод getCusomterId(). Поэтому я ничего не выиграю; метод все равно будет содержать повторения.

Я благодарен за все возможные решения, чтобы обобщить эту проблему!

+1

так, классы все реализовать 'Invoice', и все реализовать' getCustomerId', но ' getCustomerId' не находится в интерфейсе 'Invoice'? Вам нужно будет использовать отражение, чтобы получить доступ к методу по имени и вызвать его. На данный момент интерфейс 'Invoice' совершенно бесполезен. – njzk2

+0

«getInsuranceInvoices',' getBankInvoices' ... все четыре возвращают одинаковое количество счетов-фактур? – Rajesh

+3

У меня есть предложение ... применить cluebat к человеку, который сделал интерфейс «Invoice» интерфейсом маркера вместо того, который указывает, какие методы имеют счета-фактуры. – Powerlord

ответ

7

Возможные решения обобщать проблему (упорядоченные от лучшего к худшему):

Использование обертки класса

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 Если я правильно понял, что вам нужно сделать что-то с Идентификаторы во всех массивах.Чтобы использовать InvoiceWrapper, вам также нужно реализовать итератор в классе Helper, который будет проходить через массивы и возвращать обертку для каждой записи. Таким образом, в любом случае у вас будет код, который работает с 4 массивами.

Используя экземпляр слепков

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

Вызов методов по имени с помощью Reflection

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

Спасибо за ваши предложения! Первый подход - это то, что я не принимал во внимание. Но не могли бы вы объяснить мне, почему вы выбрали подход «Отражение», чтобы быть худшим из трех? – DeMo

+1

@DeMo Это потому, что если кто-то удалит метод, вы его не заметите. В первых двух вариантах вы увидите ошибку компиляции. – AdamSkywalker

2

Это не красиво, но вы могли использовать отражение для поиска getCustomerIdMethod и затем invoke() его, ср Class.getDeclaredMethod().

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

Обратите внимание, что это не тестировалась.

2

Если вам не разрешено изменять классы, с которыми вы работаете, добавив к ним настраиваемый интерфейс. Лучшее, что вы можете сделать, это обернуть их специальным классом, который имеет желаемые свойства.

Таким образом, у вас будет один класс со всем «не очень приятным» кодом, который преобразует классы, которые вы не можете прикоснуться к хорошим классам, которые соответствуют правильному и полезному дизайну.

Например, у вас может быть класс WrappedInsuranceInvoice, который расширяет WrappedInsurace и содержит поле участника InsuranceInvoice. Если вам не нужно сохранять исходный класс, вы бы еще лучше, скопировав данные. Таким образом, вы можете, например, потерять массивы и использовать списки.