Template method pattern with implementation specific parameter type
Asked Answered
R

3

5

I often get into situation when I'd like to use template method pattern, but the template method expects a different type of a parameter, like this:

public abstract class AbstractFoo  {

    public void process(TypeA a, TypeB b) {

     //do common processing
        if (b == null) {
          doProcess(a);
        } else if(a == null) {
          doProcess(b);
        }
    }

    public abstract void doProcess(TypeA a);
    public abstract void doProcess(TypeB b);
}

This doesn't look good. One of the supplied paramaters would have to be null and all services would have to implement dummy doProcess methods for other types. Is there any better pattern for this? How do you deal with this ? I don't want to use constructor because these services are spring beans. Also the same problem applies to Strategy pattern.

Redeploy answered 16/7, 2011 at 5:53 Comment(0)
E
4
public abstract class AbstractFoo<T>  {

    public void process(T a) {

        //do common processing

        doProcess(a);
    }

    protected abstract void doProcess(T a);
}

public class Person extends AbstractFoo<Person> {
    @Override
    protected void doProcess(Person p) {
        p.draw();
    }
}


public class Car extends AbstractFoo<Car> {
    @Override
    protected void doProcess(Car c) {
        c.draw();
    }
}
Estray answered 16/7, 2011 at 6:21 Comment(3)
Now the problem is that he will have to create separate classes for TypeA and TypeB. I removed my previous comment to prevent confusion.Hortenciahortensa
I don't see a problem with creating two separate classes. There's a common computation that has to be done for every type and some specific in the implemented doProcess(T) method.Tripartite
I actually agree with you now. But I suggest you also show subclasses examples in your answer. That will make it crystal clear.Hortenciahortensa
E
2

You're right that it definitely isn't a template method pattern, but I'm not sure exactly what you're trying to do. Maybe you're after the factory pattern:

interface Foo {
    boolean isA();
    boolean isB();
    ...
}

class ProcessorFactory {
    public Processor getProcessor(Foo foo) {
        if (foo.isA()) {
            return new AProcessor();
        }
        if (foo.isB()) {
            return new BProcessor();
        }
        ...
    }
}

As for constructors, all of my spring beans have constructors that express their dependencies. What's wrong with that?

Elysian answered 16/7, 2011 at 6:21 Comment(1)
The example expresses exactly what I'm trying to do. Processing of types that cannot even share interface. I meant that I couldn't use constructor for supplying parameters. It would be ugly anyway...Redeploy
G
2

I think using a Wrapper class can solve this problem. Wrapper class can be a simple Holder entity. You can even consider encapsulating your application specific properties in the wrapper class (more on lines of a Context). With this approach you only need one process method and the sub classes will only process the Message if it has the correct type. To avoid code duplication you can also do that checking in your abstract class. See following example,

public class Context {
private Object body;
public Context(Object obj) {
    body = obj;
}
public Object getBody() {
    return body;
}
}

public abstract class AbstractFoo  {

public void process(Context ctx) {
 //do common processing
    if (canProcess(ctx)) {
      doProcess(ctx.getBody());
    }
}

protected abstract <T extends Object> boolean canProcess(T obj);
protected abstract <T extends Object> void doProcess(T obj);
}
Gothic answered 16/7, 2011 at 6:51 Comment(1)
Obviously you can replace the Object with your project specific interfaces.Gothic

© 2022 - 2024 — McMap. All rights reserved.