user2487795
user2487795

Reputation: 13

Programmatically declare a variable for a common method (without using an array)

I am just learning Java, but my question is both Java-related and general.

My situation is this: I have a method that I would like to use commonly by several classes, through inheritance. Inside the method block, I need to declare a variable of the calling class, create objects from it that are housed in an ArrayList<> ("array") of the calling class, and send the output through an ObjectOutputStream ("output") to a serialized file.

I have the following classes:

CustomerInternalFrame.java, which maintains an "array" of serialized Customer.java using an ArrayList of type Customer.

ContractorInternalFrame.java, which maintains an "array" of serialized Contractor.java using an ArrayList of type Contractor.

VendorInternalFrame.java, which maintains an "array" of serialized Vendor.java using an ArrayList of type Vendor.

In each of these InternalFrame classes, I have the following method, addRecords (replace "Customer" with the appropriate class, either Customer, Contractor, or Vendor):

private void addRecords() {

  // object to be written to the file
  Customer record;

  // loop until end of array
  for (Customer element : array) {

     // check for closed streamer and invalid entries
     try {

        // create a new object from current fields
        record = new Customer(
           element.getName(),
           element.getLastName(),
           element.getAddress1(),
           element.getAddress2(),
           element.getCity(),
           element.getState(),
           element.getZip(),
           element.getPhone(),
           element.getCell());

        // write new record
        output.writeObject(record);
     } // end try
     ... (catch blocks)
   } // end for
} // end method

I have thought hard and searched long for a way to programmatically change the word "Customer" in the above, so that I can declare a single method (or class) addRecords() and have each of the three InternalFrame classes use it, without having to duplicate code. I of course cannot replace the word "Customer" with "Object" in all cases, because "Object" does not have my methods getName(), getAddress1(), etc. I also cannot replace "Customer" with an "Object()" array, for the same reason. (In other words, using arrays--the normal solution--does not work in this case, because I would have to use a superclass array and then downcast it, but downcasting it requires declaring the originally-named class in the first place. So an array is just a vicious circle in this case.)

I realize having three separate addRecords() methods allows me to change whatever fields I am recording in the respective file, since Customer, Contractor, and Vendor may well have different field sets. But I have other situations that are similar, where the things I am doing in the code are identical, but called on by different classes (such as similar event handlers), and it sure would be nice to be able to know if something like this can be done at all.

So, is there any way to change a variable type, including by passing one in to a method or constructor, so that several classes can use the same code to create objects of those specific classes?

Upvotes: 1

Views: 776

Answers (1)

Boris the Spider
Boris the Spider

Reputation: 61148

Make your base class generic like so:

public abstract class InternalFrame<T> {

    protected abstract Collection<? extends T> getElements();

    protected abstract Serializable getRecord(final T t);

    public void serialize(final File file) {
        try (final ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) {
            for(final T t : getElements()) {
                oos.writeObject(getRecord(t));
            }
        } catch (IOException ex) {
            //handle
        }
    }
}

And then in your extending class you just need to implement the abstract methods

public class CustomerFrame extends InternalFrame<Customer> {

    @Override
    protected Collection<? extends Customer> getElements() {
        return array;
    }

    @Override
    protected Serializable getRecord(Customer element) {
       return new Customer(
       element.getName(),
       element.getLastName(),
       element.getAddress1(),
       element.getAddress2(),
       element.getCity(),
       element.getState(),
       element.getZip(),
       element.getPhone(),
       element.getCell());
    }

}

And you would call the serialize(final File file) method to write the records to a File.

Upvotes: 5

Related Questions