Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generalized method to get similar object attributes

I have an object which has a few arrays as fields. It's class roughly looks like this:

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

All of the invoice types have a mutual marker interface Invoices.
I need to get all of the invoices to invoke another method on them.

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

The problem is that all invoices only have the marker interface in common. The method getCustomerID() is not defined by a mutual interface or class. This is a behaviour I cannot change due to a given specification.

The code repetition inside the for-each-loop is something that bugs me. I have to do the exact same thing on all invoice objects in the four different arrays. Hence four for-each-loops that unecessary bloat the code.

Is there a way that I can write a general (private) method? One idea was:

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

But this would require four instanceof checks because the class Invoice doesn't know the method getCusomterId(). Therefore I would gain nothing; the method would still contain repetitions.

I'm thankful for every possible solution to generalize this problem!

like image 266
DeMo Avatar asked Jun 18 '15 13:06

DeMo


People also ask

How to access attributes of object in Java?

Variables that belong to an object are usually called attributes, but you might also see them called “fields”. To access an attribute of an object, Java uses dot notation. For example: int x = blank.

What is an object attribute?

Attributes. An object characteristic that is always present and occupies storage, even if the attribute does not have a value. In this respect, an attribute is similar to a field in a fixed-length data structure.

Is an attribute of an object is always a function in Python?

Yes, Python functions are objects. And because they're objects, they have attributes. And because they're objects, we can assign new attributes to them, as well as retrieve the values of those attributes.


2 Answers

Possible solutions to generalize the problem (ordered from best to worst):

Using wrapper class

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 If I understood correctly, you need to do something with IDs in all arrays. To use InvoiceWrapper, you also need to implement iterator in Helper class, that will walk through arrays and return a wrapper for each entry. So, you will have code that works with 4 arrays anyway.

Using instance of casts

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

Calling methods by name via Reflection

public class CustomerIdHelper {
    public static String getID(Invoice invoice) {
        Method method = invoice.getClass().getDeclaredMethod("getCustomerId");
        return (String) method.invoke(invoice);
    }
}
like image 194
AdamSkywalker Avatar answered Oct 31 '22 15:10

AdamSkywalker


It's not pretty, but you could use reflection to look up the getCustomerId Method and then invoke() it, 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 note that this is untested.

like image 44
jensgram Avatar answered Oct 31 '22 15:10

jensgram