Reputation: 155
Suppose I have interfaces of factory classes FactoryA
and FactoryB
with methods for producing objects of type A
and B
respectively, and suppose I have implementations of these interfaces. Now suppose I need a factory class FactoryAB
that implements both interfaces, i.e., produces both A
and B
. Is there a simple way to combine the implementations of interfaces FactoryA
and FactoryB
to get a FactoryAB
?
Edit: This is motivated by a situation where a class needs a large number of factories to produces a large number of different objects. In this case it seems to me more convenient to just have a single large factory that produces all the needed components instead of having to keep track of many small factories.
The main goal is to not have to write too much code to achieve this. Perhaps, some other pattern is more appropriate for this scenario?
Edit2: Essentially I would like to go from having bloated code like:
public class Consumer {
FactoryA factoryAImpl;
FactoryB factoryBImpl;
// ...
FactoryY factoryYImpl;
FactoryZ factoryZImpl;
public Consumer(FactoryA factoryA, FactoryB factoryB, ..., FactoryZ factoryZ) {
// ...
}
//...
}
To having compact/simple code like:
public class Consumer {
FactoryAtoZ factoryAtoZImpl;
public Consumer(FactoryAtoZ factoryAtoZ) {
// ...
}
//...
}
Upvotes: 0
Views: 608
Reputation: 21184
You could do this by dynamically generating a Proxy and delegating the method calls to the concrete objects if and only if you have a reliable way of determining which delegate to hand this off to.
First of all you're going to need an interface that combines your existing factories
public interface FactoryAB extends FactoryA, FactoryB {
}
(note that lack of methods)
Then you need to create the Proxy
DelegatingHandler handler = new DelegatingHandler(new ConcreteFactoryA(), new ConcreteFactoryB());
FactoryAB factoryAb = (FactoryAB)Proxy.newProxyInstance(handler.getClass().getClassLoader(), new Class[]{FactoryAB.class}, handler);
And finally the InvocationHandler
to do the actual method interception for you
public class DelegatingHandler implements InvocationHandler {
private final List<Object> factoryDelegates;
public DelegatingHandler(Object ... factories) {
factoryDelegates = Arrays.asList(factories);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
for (Object factory : factoryDelegates) {
Method[] declaredMethods = factory.getClass().getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
if (declaredMethod.getReturnType().equals(method.getReturnType())) {
return method.invoke(factory, args);
}
}
};
return null;
}
}
This works by providing a list of concrete factories to delegate to, and on every method call looks at these factories to find one that has a method that matches the return type. When it finds one it will invoke the method you called on the delegate factory and return whatever it returns.
I suspect you might need more involved checking to find the right delegate, but only you know that.
Using this you can add new factories to your delegate by merely adding to the FactoryAB
interface and injecting the required delegate into the DelegatingHandler
, no further work required.
You should note that using this method, all of your calls are now being routed by reflection instead of direct method calls
Upvotes: 1
Reputation: 159
You can use composite concept and factory method pattern to combine both FactoryA
and FactoryB
interfaces. Assuming you have a common interface AB
and public A getA()
the factory method for FactoryA
and public B getB()
the factory method for FactoryB
:
public class ABFactory implements FactoryA, FactoryB {
public AB GetAB(InterfaceType type) {
AB implementation = null;
switch (type)
{
case InterfaceType.AType:
implementation = getA();
break;
case InterfaceType.BType:
implementation = getB();
break;
default:
break;
}
return implementation;
}
public A getA() {
return new FactoryAImpl().getA();
}
public B getB() {
return new FactoryBImpl().getB();
}
}
assuming
public enum InterfaceType {
AType,
BType
}
Upvotes: 0
Reputation: 816
You could do it with Composition:
public class FactoryAB implements FactoryA, FactoryB
{
FactoryA factoryAImpl = new FactoryAImplementor();
FactoryB factoryBImpl = new FactoryBImplementor();
public ObjectA getObjectA() {
return factoryAImpl.getObjectA();
}
public ObjectB getObjectB() {
return factoryBImpl.getObjectB();
}
}
Upvotes: 4