1

I have in my application three classes User, Group, Company which do not belong to the same inheritance tree, as their names reveal. Each class has a constructor which receives a number of (different) parameters i.e: User(String name, String password, int type), Group(String name, String name), Company(String name, int employees, boolean isValid). The number of the paraameters that each constructors requires is not the same for all the classes. I have created a class ReadDataFromFile to read some data from txt files and to create new Objects passing the data as paaraameters to the above constructors. The code of this class is apparently the same for every type, except for one method which creates the objects. Consequently it is not appropriate to create three distinct classes, but I had better to aim at a better design approach.

My question is whether the opportune design on this occasion is a Generic class, or an abstract class and implementing in its subclass the one method which differs createObject(), assuming that the necessary data coming from the txt file are put into a String array with differnt length for each type. I would like to follow the approach of Generic class: class ReadDataFromFile<T>{} , but I cannot find how I should handle the different types, since each one requires a call of a different constructor. Should I check for the type with instanceof? Should I pass to the method the class of each object? Or is there a better way?

arjacsoh
  • 8,932
  • 28
  • 106
  • 166

4 Answers4

2

Do not understand why you have posed the question as "abstract or generic" it looks like the common solution would be both.

public abstract class ReadFromFile<T> {

  public T readFile(File file) {
    String[] rawInput = doSomeStuffCommonToAll();
    return constructObject(rawInput);
  }

  abstract T constructObject(String[] rawInput);
}

public class UserFileReader extends ReadFromFile<User> {

  @Override
  User constructObject(String[] rawInput) {
    return new User(rawInput[0], rawInput[1], Integer.parseInt(rawInput[2]);
  }
}
Affe
  • 47,174
  • 11
  • 83
  • 83
  • It seems a good solution. I 'll try it. I thought if it were a way to put it through only with generics to avoid creating four classes. – arjacsoh Feb 26 '13 at 20:51
  • Generics are a compile-time-only feature in Java. They cannot do anything to solve for you the problem of choosing what code path to execute based on *run-time* inputs. – Affe Feb 26 '13 at 20:53
0

Create your objects based on conditions, for example the "instanceof" validation:

if (objectData instanceof User){
 User = new User();
 user.setName(objectData.getString(1));
} //...
Marcelo Tataje
  • 3,849
  • 1
  • 26
  • 51
0

I think I would choose an abstract design and for instance make use of the abstract factory pattern.

gilgamash
  • 862
  • 10
  • 31
0

The answer in short, is neither :) Yes you do need abstraction, but it does not have to be of the subclassing form you seem to be leaning towards. Prefer composition over inheritance?

Long answer :) I do not know your domain exactly, but from what you have written I'm assuming you have three files, users.txt, groups.txt and companies.txt, with a shared format but with different data - something like CSV. So you can achieve abstraction through composition by doing something like this, which should illustrate the point even if my assumptions are wrong.

public class FileReader {
    public static void read(File f, RowHandler rowHandler) {
        //read each line, convert its contents to a map, and pass it to rowHandler
    }
}

where

public interface RowHandler {
    void handle(Map<String,String> row);
}

This means you separate the reading and parsing of each line from what do to with each parsed line.

To create User objects you could do:

public class UserConstructor implements RowHandler {
    private List<User> users = new ArrayList<User);

    public void handle(Map<String,String> row) {
        users.add(new User(row.get("name"), row.get("password"), Integer.parseInt(row.get("type)));
    }

    public List<User> getUsers() {
        return users;
    }
}

And then you connect it all by doing

UserConstructor uc = new UserConstructor();
FileReader.readFile(new File("users.txt), uc);
List<User> users = uc.users();

You use the class name ReadDataFromFile. This name suggests a single purpose, but your question suggests you're mixing another concern into it - so it reads files and creates objects. ReadDataFromFile should just read data from file, and pass the data to another class to implement a strategy to do something with it.

Thats what the above design attempts to do - keep concerns separate.

Community
  • 1
  • 1
Mike Hogan
  • 9,933
  • 9
  • 41
  • 71