Reputation: 51
Let's say I have a class named Human
in ProjectA
. It is instantiated in the CreatureBuilder
class of the same project.
Now I want to create a new class called Cyborg
in a different project, i.e. in ProjectB
. ProjectB
has ProjectA
in its imports, but ProjectA
knows nothing about ProjectB
.
Cyborg extends Human
, and must also be instantiated by CreatureBuilder
of ProjectA
(so, Cyborg
is located in ProjectB
, I call CreatureBuilder
from ProjectB
to instantiate Cyborg
, but CreatureBuilder
is located in ProjectA
, as well as my Human
class).
I need a logic to create a Human
when CreatureBuilder
is instantiated from ProjectA
, and to create a Cyborg
when CreatureBuilder
is instantiated from ProjectB
.
I know that it can be done by creating an interface with a getCreature()
method (that will be overridden in ProjectB
) and a factory class.
But can I use Reflection API instead? From its description, looks like it was designed to do something related (please correct me if I'm wrong). I know that reflections are slow though, and I normally avoid them. But it would be great to see a proof-of-concept, just out of curiosity.
Upvotes: 0
Views: 53
Reputation: 31225
You can do that with Class.forName()
if you predefine the fully qualified name of a HumanFactory
.
Let's say that this HumanFactory
must have this fully qualified name : com.mycompany.HumanFactory
.
In Project A :
First, declare the interface of a HumanFactory
:
public interface HumanFactoryItf() {
Human newHuman();
}
Then, here is a stub for a CreatureBuilder
:
public class CreatureBuilder {
public Human build() {
try {
HumanFactoryItf factory =
(HumanFactoryItf)Class.forName("com.mycompany.HumanFactory").newInstance();
return factory.newHuman();
} catch(ClassNotFoundException e) {
return new Human();
}
}
}
In ProjectB :
package com.mycompany;
public class HumanFactory implements HumanFactoryItf {
public Human newHuman() {
return new Cyborg();
}
}
And from the main class :
public static void main(String[] args) {
CreatureBuidler cb = ...
/*
This line : class.forName("com.mycompany.HumanFactory")
will end up instantiating the HumanFactory of ProjectB.
*/
Human h = cb.build();
}
FYI, slf4j uses this pattern in order to decide which logger implementation to use.
Upvotes: 0
Reputation: 27984
Sounds like you want to use generics
public class CreatureBuilder<T extends Creature> {
private Class<T> type;
public CreatureBuilder<T>(Class<T> type) {
this.type = type;
}
public T build() {
return type.newInstance();
}
}
CreatureBuilder<Human> humanBuilder = new CreatureBuilder<>(Human.class);
Upvotes: 0