views:

182

answers:

5

I have two classes. SpeciesReader takes files and parses them. Species stores certain data about a species, which has been parsed from the file.

Currently, I have a method: SpeciesReader.generateSpecies(), which uses the file with which it was instantiated to create a Species object. Is this bad practice/design? Should I somehow find a way to move this to a constructor in Species that takes the filename as an argument?

+7  A: 

Not at all. That's a common pattern called a factory.

That being said, factories are usually implemented on the class itself (Species in this case) rather than a separate class but I see no problem with separating it like that.

As for whether this responsibility should go on Species instead, that depends on the nature of the files. If a file contains merely one Species and there's no large overhead in loading that file then it might make sense to make it part of Species.

But if the file contains lots of species or is expensive to initialize then it makes perfect sense to move that responsibility to another class and have it be responsible for creating Species objects.

cletus
+1 for factory - it's probably worth adding a link to further reading material on the factory pattern
Bob Cross
A: 

There are a few patterns you could use:

The choice of which pattern to implement would depend on use case, but Cletus is correct, factory seems like a good choice.

public class SpeciesFactory
{
    private final static SpeciesFactory INSTANCE = new SpeciesFactory();

    private SpeciesFactory() { }

    public static SpeciesFactory getFactory() 
    {
        return INSTANCE;
    }


    public Species getSpecies(String filename)
    {
        Species species = null;
        //do business logic
        return species;
    }

}

You would use it by calling Species carnivore = SpeciesFactory.getFactory().getSpecies("carnivore.txt");

Droo
why not just SpeciesFactory.getSpecies()? (making it static)
Rosarch
As a general rule, I try to stay away from using static methods. In the above example, the JVM only has one instance of SpeciesFactory and the singleton INSTANCE reassures that only one factory will ever be instantiated. Regardless of object reference, what if you wanted to cache certain species in your species accessor? You wouldn't want do that with a Util class that has static methods or a public constructor.
Droo
A: 

What you have is an example of the Factory Method Pattern. This creational pattern can be used well in some cases. My personal preference however is to try and restrict it usage to only that of a more readable replacement for a ctor and not do anything overly complex within it. This is to simplify testing of any classes that depend on this factory.

For something with a complex construction I would use Abstract Factory. This way I can test components with a dependency on said factory without creating a bunch of files and any other dependencies the factory has.

Above you ask about having a Singleton vs a static method in factory. My take on this is: A static method is good for readable ctors, a singleton is good irritating anyone with a preference for unit testing.

mlk
A: 

It's a good idea to separate the parsing of a file from the implementation of objects parsed from that file. This is known as "Separation of Concerns". The implementation of Species should not know or care how it is represented in persistent storage (in OO design jargon, it should be "persistence agnostic") or where the parameters passed to its constructor come from. It should only care about how interacts with other objects in the system once it has been created, however that creation occurs. The concern of how Species are represented in persistent storage should be implemented elsewhere, in your case in the SpeciesReader.

Nat
A: 

It is often better idea to separate object from the way it is persisted. Imagine if there are many ways to load Species - from binary file, from xml file, from database record, from network socket, etc - poor Species does not want to know about every part of your program.

Pavel Feldman