I have a Base interface that defines some common functionality. Now this base interface can be implemented by more than 50 classes each having some different additional methods. I want to have a static factory that will return an instance of any one of 50 classes depending on a parameter pass to that static factory method.
public interface Base {
public void a();
public void b();
}
public class myclass implements Base {
// a and b implementation
public String c() {
}
public String d() {
}
}
public class secondclass implements Base {
// a and b implementation
public String e() {
}
public String f() {
}
}
How can I implement a static factory method. I am unsure of return type
public synchronized static {return type} getInstance(String arg0) {
// do something and return any one class based on arg0
}
EDITS: A scenario
If the passed parameter is 300
I want to return object of class myclass
If parameter is 900
I want to return object of class secondclass
And so on. having so many conditions is not feasible.
NOT TO DO
public synchronized static {return type} getInstance(String arg0) {
// do something and return any one class based on arg0
if(arg0.equals("300")) {
return new myclass();
}
}
REASON: This will not be salable. I am developing a public API and class list may increase to 100 or may be 500. I hope my question is more clear now.
UPDATE: Very useful points highlighted here and this is what I thought of
public abstract class Base {
public abstract void a();
public abstract void b();
public synchronized staticabstract Base getInstance(String arg0);
}
public class myclass extends Base {
private myclass() {} // private constructor not publicly instantiate
// a and b implementation
public void c();
public void d();
@Override
public synchronized static abstract Base getInstance(String arg0) {
if(arg0.equalsIgnoreCase("300")) { // only 1 if condition
return new myclass();
}
}
}
public class secondclass extends Base {
private secondclass() {} // private constructor not publicly instantiate
// a and b implementation
public void e();
public void f();
@Override
public synchronized static abstract Base getInstance(String arg0) {
if(arg0.equalsIgnoreCase("900")) { // only 1 if condition
return new secondclass();
}
}
}
Client side:
one applicaiton
Base b=Base.getInstance(300);
if(b instanceof myclass) {
}
second application
Base b=Base.getInstance(900);
if(b instanceof secondclass) {
}
A better approach would be to generify the static method:
static <T extends Base> T create(Class<T> type){
// create concrete instance of type T and return it
}
so now the create
method is parameterized by the actual concrete type Class
object. You can use type
to create the appropriate sub-type, either via reflection or using nested if
statements.
Using generics has the advantage of giving you strong type safety for free, so you can avoid unchecked casts and go home after work with no worries.
EDIT: as an example if you had a no-arg constructor in each sub-class you could implement the above as:
return type.newInstance();
EDIT 2: To sum up the discussion, if the factory can't take the type or the logic to create the object depends in a non trivial way on the value of the argument, the only option is the following:
static Base create(String someParameter){
// create the concrete class and return it
}
And the client code will look like:
Base b = create("myArgument");
if(b instanceof SomeDerived){
SomeDerived d = (SomeDerived) b;
// use d
} else if(b instanceof OtherDerived){
// you get the idea
}
Not ideal but there's no way to generify the create
method without an instance of Class<? extends Base>
.
One of the relevant reasons of using static factory over constructors (quote from Effective Java):
A third advantage of static factory methods is that, unlike constructors, they can return an object of any subtype of their return type
So, essentially it can give you ability to write something like :
Base x = Factory.getInstance(TypeX.class);
x.methodOfBase();
where TypeX
could be completely hidden and have private constructor.
You may want to have a look at java.util.Collections
API implementation, for instance consider static factory method :
public static <T> List<T> synchronizedList(List<T> list)
as you see return type is an interface, and therefore returned object(some hidden implementation of List
) could only be used as a List.
So if you want to use methods x1()
, x2()
which are exclusive to subtype TypeX
and do not belong to Base
interface, you will have to cast your object to TypeX
anyway.
In this case you can instantiate TypeX
directly via constructor (by keeping it public), as static factory won't give you anything.
You may also want to have a look at other 3 reasons to use static factory
over constructors
in the book and verify that non of them are applicable to what you described in your question so far.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With