I am trying to design a factory for a pluggable interface. The idea is that once you have your factory instance, the factory will return the appropriate subclasses for that particular implementation.
In this case, I am wrapping a third party library that uses a String to represent an ID code, rather than subclasses. Therefore, in the implementation that wraps their library, every implementation class has a method getCode()
that is not explicitly required by the interface API. I am using an enum
to store this mapping between codes and interface classes.
In nearly all cases, the getCode()
method is not needed. However, in just a few situations in the implementation package, I need access to that method. Therefore, my problem is that I would like to have the Factory implementation's signature tell callers that the getCode
method exists if they have a reference to the specific Factory implementation.
What follows is a lot of code in my best-effort attempt to digest the situation into an sscce. I know it's very long, but it's simpler than it seems, and one of the words in sscce is "complete".
Public API:
public interface Factory {
public <T extends IFoo> T makeIFoo(Class<T> klass);
}
public interface IFoo {
void doSomething();
}
public interface IFooBar extends IFoo {
void doBarTask();
}
public interface IFooBaz extends IFoo {
void doBazTask();
}
Sample use case:
public class SomeClass {
private Factory myFactory;
public void doSomething() {
IFooBar ifb = myFactory.create(IFooBar.class);
}
}
SSCCE version of implementation:
interface ICode {
String getCode();
}
abstract class BaseCode implements IFoo, ICode {
private String code;
BaseCode(String code) {
this.code = code;
}
@Override
public String getCode() {
return code;
}
@Override
public void doSomething() {
System.out.println("Something");
}
}
class FooBarImpl extends BaseCode implements ICode, IFooBar {
FooBarImpl(String code) {
super(code);
}
@Override
public void doBarTask() {
System.out.println("BarTask");
}
}
class FooBazImpl extends BaseCode implements ICode, IFooBaz {
FooBazImpl(String code) {
super(code);
}
@Override
public void doBazTask() {
System.out.println("BarTask");
}
}
Enum codemapper:
static enum CodeMap {
FOOBAR ("A", IFooBar.class) {
FooBarImpl create() { return new FooBarImpl(getCode()); }
},
FOOBAZ ("B", IFooBaz.class) {
FooBazImpl create() { return new FooBazImpl(getCode()); }
};
private static Map<Class<? extends IFoo>, CodeMap> classMap;
static {
classMap = new HashMap<Class<? extends IFoo>, CodeMap>();
for(CodeMap cm : CodeMap.values()) {
classMap.put(cm.getFooClass(), cm);
}
}
private String code;
private Class<? extends IFoo> klass;
private CodeMap(String code, Class<? extends IFoo> klass) {
this.code = code;
this.klass = klass;
}
String getCode() {
return code;
}
Class<? extends IFoo> getFooClass() {
return klass;
}
static CodeMap getFromClass(Class<? extends IFoo> klass) {
return classMap.get(klass);
}
abstract BaseCode create();
}
Sample use case within implementation package:
public class InternalClass {
CodeFactory factory;
public void doSomething() {
FooBarImpl fb = factory.makeIFoo(IFooBar.class);
}
}
Attempt at factory:
This does not specify that the return will always implement ICode
. But the passed-in interface class DOESN'T implement ICode
, that's the whole point.
class CodeFactory implements Factory {
@Override
public <T extends IFoo> T makeIFoo(Class<T> klass) {
CodeMap map = CodeMap.getFromClass(klass);
if (map == null) return null; // Or throw an exception, whatever, SSCCE
return (T) map.create();
}
}
What should I do?