Reputation: 135
So I have the following structure:
public abstract class Processor<T extends BaseContainer> {
protected abstract T initializeContainer(String requestID, Map<String, String> details);
protected abstract boolean validateContainer(T request);
protected abstract void process(T request);
public final process(String requestID, Map<String, String> details) {
T request = initializeContainer(requestID, details);
if (!validateContainer(request)) {
process(request);
}
}
}
public abstract class BaseContainer() {
protected final String requestID;
protected BaseContainer(String requestID, Map<String, String> details) {
this.requestID = requestID;
// set some other fields using details
}
}
Everytime I need to add a new Processor (with a corresponding new Container), I will need to:
public class SampleProcessor extends Processor<SampleContainer> {
@Override
protected SampleContainer initializeContainer(String requestID, Map<String, String> details) {
return new SampleContainer(requestID, details);
}
}
// SampleContainer can contain other details, but omitted for clarity
public class SampleContainer extends BaseContainer {
public SampleContainer(String requestID, Map<String, String> details) {
super(requestID, details);
}
}
I don't like the fact that I need to override initializeContainer
for every Processor I add, especially when I don't change the constructor's parameters of Container (it will be always String requestID, Map<String, String> details
I understand that I can't simple call new T(requestID, details)
in Processor
. And I would imagine I will need some sort of factory (?) if I want to implement initializeContainer
at base class.
Can you help to suggest anyway I can achieve this? Thank you.
Edit 1: I added two more methods to provide better context Processor
Upvotes: 1
Views: 94
Reputation: 1986
This is a pattern called the abstract-factory.
Everytime I need to add a new Processor (with a corresponding new Container), I will need to:
This is the main intend of the pattern (ebenda)
the client (you) software creates a concrete implementation (your SampleProcessor) of the abstract factory (Processor) and then uses the generic interface of the factory to create (via initializeContainer) the concrete objects (your SampleContainer)...
Upvotes: 1
Reputation: 114777
I'd refactor the method name to createContainer
, because that's what you do with your implementation - you don't setup an existing one but the make a new one.
Your simple example only calls the container constructor. But the 'processor creation and initialization' process could vary. Maybe, some processors for some container need special treatment. Then the implementations of the method would look different for each container subclass again.
An alternative common pattern, to solve this common problem, would be adding another abstract method like
public abstract Class<T> getProcessorType();
and implement it like this on every container implementation:
@Override
public Class<MyProcessor> getProcessorType() {
return MyProcessor.class;
}
The base class then could implement the create method for processors:
public T createProcessor(String requestID, Map<String, String> details) {
T processor;
try {
processor = getProcessorType().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace(); // or handle correctly
}
processor.init(requestId, details)
return processor;
}
(Note that this requires a no-args processor constructor)
Upvotes: 0