The purpose of the factory pattern is to de-couple some code from the run-time type of an object it consumes:
// This code doesn't need to know that the factory is returning
// an object of type `com.example.parties.SurpriseParty`
AbstractParty myParty = new PartyFactory().create(...);
Using code like this, the PartyFactory
is exclusively responsible for determining or knowing exactly what run-time type should be used.
You're forgoing that benefit by passing in the fully qualified name of the class you need. How is this...
// This code obviously DOES know that the factory is returning
// an object of type `com.example.parties.SurpriseParty`.
// Now only the compiler doesn't know or enforce that relationship.
AbstractParty myParty = new PartyFactory().create("com.example.parties.SurpriseParty");
... any different from simply declaring myParty
as being of type com.example.parties.SurpriseParty
? In the end your code is just as coupled, but you've given up static type verification. That's means you're incurring less than no benefit while surrendering some of the benefits of Java being strongly typed. If you delete com.example.parties.SurpriseParty
your code will still compile, your IDE will give you no error messages and you won't realize there was a relationship between this code and com.example.parties.SurpriseParty
until run time - that's bad.
At the very least, I'd advise you to at least change this code so the method's argument is a simple class name, not a fully qualified name:
// I took the liberty of renaming this class and it's only method
public class MyPartyFactory{
public Party create(String name)
{
//TODO: sanitize `name` - check it contains no `.` characters
Class c = Class.forName("com.example.parties."+name);
// I'm going to take for granted that I don't have to explain how or why `party` shouldn't be an instance variable.
Party party = (PersonalParty)c.newInstance();
return party;
}
}
Next: is it bad practice to use Class.forName(...)
? That depends on what the alternative is, and the relationship between those String
arguments (name
) and the classes this factory will provide. If the alternative is a big conditional:
if("SurpriseParty".equals(name) {
return new com.example.parties.SurpriseParty();
}
else if("GoodbyeParty".equals(name)) {
return new com.example.parties.GoodbyeParty();
}
else if("PartyOfFive".equals(name)) {
return new com.example.parties.PartyOfFive();
}
else if(/* ... */) {
// ...
}
// etc, etc etc
... that's not scalable. Since there is an obvious observable relationship between the names of the run-time types this factory creates and the value of the name
argument, You should consider using Class.forName
instead. That way your Factory
object is protected from needing a code change every time you add a new Party
type to the system.
Something else you could consider is using the AbstractFactory pattern instead. If your consuming code looks like this:
AbstractParty sParty = new PartyFactory().create("SurpriseParty");
AbstractParty gbParty = new PartyFactory().create("GoodByeParty");
... where there are a limited number of often-occurring party types which are requested, you should consider having different methods for those different types of parties:
public class PartyFactory {
public Party getSurpriseParty() { ... }
public Party getGoodByeParty() { ... }
}
... which will allow you to leverage Java's static typing.
This solution does, however, mean that every time you add a new type of Party
you have to change the factory object - so whether the reflective solution or the AbstractFactory
is a better solution really depends on how often and how quickly you'll be adding Party
types. A new type every day? Use reflection. A new party type every decade? Use an AbstractFactory
.