Working with Generics is definitely my weak spot, and can use some help with this.
The project is to develop a simple order/inventory system that places orders, keeps track of items and inventories, and keeps a record of all inventory and customer addition/removals since the program first started. This requires reading and writing to a file, and I've picked the CSV format to parse. There are two files to parse, one for Customers
and one for Items
.
I want to use a TreeSet to make additions/searches log N, but am having some trouble with my file parsing. Rather than have two classes with duplicate code working for their object type, I'd like to have a single parse class taking in the set and file path on execut开发者_如何学编程ion, and processing the file into a complete set of objects, both of whom have differing fields and methods.
The only solution I've come up with is TreeSet<? extends Object>
, but that means that I'll have to box, then unbox each object as its accessed in the structure.
Is there an easier way?
Here's an example of what your hierarchy could look like
class CVSParser<T> {
private final RecordHandler<T> handler;
public CVSParser<T>(RecordHandler<T> handler) {
this.handler = handler;
}
public Set<T> parse(File f) {
Set<T> records = new TreeSet<T>();
for (String line : file ) { //I'm paraphrasing here
records.add(handler.parse( splitIntoFields(line) ));
}
}
}
interface RecordHandler<T> {
public T parse(String[] fields);
}
class CustomerHandler implements RecordHandler<Customer> {
public Customer parse(String[] fields) {
return new Customer(fields[0], fields[1]);
}
}
class ItemHandler implements RecordHandler<Item> {
//...
}
Set<Item> items = new CVSParser<Item>(new ItemHandler()).parse(itemsFile);
Alternatively you could push the generics down to the method level of CVSParser
and make it static even:
class CVSParser {
public static <T> Set<T> parse(RecordHandler<T> handler, File f) {
//...
}
}
Set<Item> items = CVSParser.parse(new ItemHandler(), itemsFile);
Are you looking for
interface CSVParseableObject {
// routines
}
public class Customers implements CSVParseableObject{}
public class Items implements CSVParseableObject{}
And then
TreeSet<CSVParseableObject>
In which you parse can use e.g.,
Set<CSVParseableObject> parse(String path) {
Set<CSVParseableObject> parseableObjects = new TreeSet<CSVParseableObject>();
File file = new File(path);
// parse ...
return parseableObjects;
}
Here is an option:
Design a class to represent an Inventory item, and have that extend or (better) implement your parsing interface. In this way, you can simply insert the Inventory object into your tree.
E.g., TreeSet<Inventory> tree = TreeSet<Inventory>()
tree.add(Inventory Object), etc.
Guess you are confused indeed.
Each file represents data from a different object type (Customers and Items), so their formats are different, so are their fields. You can't have the same code parse them both.
I'd like to have a single parse class taking in the set and file path on execution, and processing the file into a complete set of objects, both of whom have differing fields and methods.
You can have a single class, but you'll need different code to read the two different file types. It's not the fact that you wish to fill a generic collection object that will avoid you from handling each file type in its own way. Generics is only intended to save you some manual casting and avoiding accidental addition of unwanted objects into collections.
You can do something like this in your code:
class MyParser {
public Set<Customer> readCustomersFile(String path) {...}
public Set<Item> readItemsFile(String path) {...}
}
You could do it with a less "custom-code" way... an embedded database maybe... but if that's how you wish to do now, you'll learn new ways do to the same thing as time passes.
精彩评论