Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Reflection in factory pattern [closed]

Is it a good practice to use Reflection in Factory pattern?

public class MyObjectFactory{
private Party party;

public Party getObject(String fullyqualifiedPath)
{
  Class c = Class.forName(fullyqualifiedPath);
  party = (PersonalParty)c.newInstance();
  return party;
}
}

PersonalParty implements Party

like image 414
Ullas Avatar asked Aug 25 '13 18:08

Ullas


People also ask

Can we use abstract class in factory design pattern?

Short answer: Yes. Actually, since Java 8 you can provide default implementations for the methods in an interface and the only differences to an abstract class are constructors (which you don't use anyway apparently) and fields which should be private, so there's very little difference.

What is reflection design pattern?

The use of reflection in the receiver entity of a design pattern enables the loose coupling required for transparent software evolution when unanticipated changes occur. Key to reflective design patterns is the absence of hard-coded references within the method code of both the delegates and the receiver.

What are the consequences of applying the GOF factory method pattern?

Here are two additional consequences of the Factory Method pattern: Provides hooks for subclasses. Creating objects inside a class with a factory method is always more flexible than creating an object directly. Factory Method gives subclasses a hook for providing an extended version of an object.

When should we use abstract factory pattern?

When to Use Abstract Factory Pattern: The client is independent of how we create and compose the objects in the system. The system consists of multiple families of objects, and these families are designed to be used together. We need a run-time value to construct a particular dependency.


2 Answers

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.

like image 96
Richard JP Le Guen Avatar answered Sep 23 '22 01:09

Richard JP Le Guen


Using reflection it this way (Class.forName) is almost always sign of bad application design. There are some kinds, where its use is OK, for example if you are doing some kind of dynamic load of external libraries or plugins.

like image 21
Martin Perry Avatar answered Sep 27 '22 01:09

Martin Perry