Обобщенный метод для получения похожих атрибутов объекта

У меня есть объект, который имеет несколько массивов в качестве полей. Это класс примерно выглядит так:

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 меня беспокоит. Я должен сделать одно и то же для всех объектов счетов в четырех разных массивах. Отсюда четыре цикла for-each, которые излишне раздувают код.

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

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

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

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

3 ответа

Решение

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

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

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);
    }
}

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

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

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

Это не красиво, но вы можете использовать отражение, чтобы посмотреть вверх getCustomerId Метод, а затем вызвать () его, ср. Class.getDeclaredMethod ().

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

Обратите внимание, что это не проверено.

Другие вопросы по тегам