Обобщенный метод для получения похожих атрибутов объекта
У меня есть объект, который имеет несколько массивов в качестве полей. Это класс примерно выглядит так:
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) {
// ...
}
}
Обратите внимание, что это не проверено.