简体   繁体   中英

How to create instance of generic class with parameters

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

Everythings fine

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)...

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM