views:

107

answers:

5

I have an abstract class A and several implementations of it. I expect this to evolve over time, by adding more implementations.

I also have an interface that does something at instances of the above class hierarchy (eg print them).

I want implementations of the interface to provide some special functionality for some of the subclasses of A and a default functionality for the rest of them.

I hope this example clarifies things:

abstract class A { }
class B extends A { }
class C extends A { }

interface Processor  {
    public void process(A a);
}

class SimpleProcessor implements Processor {

    //I want this to be called when argument is instance of A or C or any
    //new class that will be added in the future
    public void process(A a) {
        //Line 14
        System.out.println("Default processing");
    }

    //I want this to be called when argument is instance of B
    public void process(B b) {
        System.out.println("Special processing");
    }

}

public class Runner {

    public static void main(String[] args) {
        B b = new B();
        Processor p = new SimpleProcessor();
        p.process(b);
    }

}

The example prints "Default processing". The problem is that the method to be executed is chosen based at the compile-time type of the interface's method. Is there a way (or design pattern) to make this program print "Special processing" without adding at line 14 a list of

if (a instance of B)
  process( (B) a );

for every class that needs special processing?

I had a look at the visitor pattern but it doesn't seem like an improvement because I don't want to "pollute" the Processor interface with methods for every subclass of A because more subclasses of A will be added.

To put it another way, I want the implementations of the interface to:

  • provide custom implementation of the method for specific subclasses of A
  • provide a default implementation for classes that will be added in the future
  • avoid listing all the classes in a large if-then-else list

Thanks!!

+2  A: 

How about if you create an Adapter which take the object you want to process and return the processor for that object?

if A -> return ProcessorA
if B -> return ProcessorB

code example:

class Adapter {

    Processor getProcessor(Object o) {
        if (o instance of A) {
            return new ProcessorA();
        } else if ...
    }

}
nanda
Thanks for the reply. I was thinking of something similar. Create an AbstractProcessor implementation which has overloaded methods for every subclass of A and an entry method with the if-then-else statements. Inside the if I can have an explicit casting to the specific subclass of A. Thus, subclasses of Processor can handle new types of A and I can add processor without any changes at A or subclasses. However my concern is that it just doesn't look very OO to have huge if-then-else blocks that test for type. I was wondering if there is a better approach.
idrosid
You can put the mapping on properties file or XML, then you won't have a big list of if-then-else. Or... let I try to code it first...
nanda
+1 Adapter is a better choice here than extending the main class and using simple polymorfism as it helps to keep "service" code (logging, printing, drawing, ...) out of the main class.
Marjan Venema
+4  A: 

Move the code into the type which varies and use polymorphism. See Open Closed Principle.

interface Processable  {
    void process();
}

abstract class A implements Processable {
    public void process() {
        System.out.println("Default processing");
    }
}
class B extends A {
    public void process() {
        System.out.println("Special processing");
    }
}
class C extends A {
    // default implementation inherited from A
}


class SimpleProcessor {
    public void process(Processable p) {
        p.process()
    }
}

public class Runner {
    public static void main(String[] args) {
        B b = new B();
        Processor p = new SimpleProcessor();
        p.process(b);
    }
}
Esko Luontola
Thanks for the reply.The problem is that I would like to have many Processor implementation.To make things more concrete, class A is a UI widget and Processor is a renderer for the widgets. I want to be able to add more renderers (for example more skins). I also want to add more widgets (by subclassing existing widgets) and have the flexibility to update only some of the renderers.So, both subclasses of A and of Processor vary, so the approach you suggest does not solve the problem.
idrosid
Problem with this is that you have to put a lot of "service" code in classes that shouldn't concern themselves with those services (logging, printing, drawing, ...). Using an Adapter is as flexible and keeps the "service" code out of the main classes.
Marjan Venema
A: 

This is a further improvement of using Adapter. This solution needs Reflections library from: http://code.google.com/p/reflections/

Advantage:

  • no if then else with instanceof
  • no configuration

Disadvantage:

  • Need Reflections library
  • Can be slow in the beginning

This is it:

import java.lang.reflect.ParameterizedType;

public abstract class Processor<T> {

    private final Class<T> processedClass;

    public Processor() {
        ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
        processedClass = (Class<T>) parameterizedType.getActualTypeArguments()[0];
    }

    public Class<T> getProcessedClass() {
        return processedClass;
    }

    protected abstract void process(T message);

}

public class A {

}

public class B {

}

public class ProcessorA extends Processor<A> {

    @Override
    protected void process(A message) {
        System.out.println("Processing object A");
    }

}

public class ProcessorB extends Processor<B> {

    @Override
    protected void process(B message) {
        System.out.println("Processing object B");
    }

}

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.reflections.Reflections;

public class Adapter {

    private Map<Class<?>, Processor<Class<?>>> mapping = new HashMap<Class<?>, Processor<Class<?>>>();

    public Adapter() throws Exception {
        Reflections r = new Reflections("");
        Set<Class<? extends Processor>> subTypesOf = r.getSubTypesOf(Processor.class);

        for (Iterator iterator = subTypesOf.iterator(); iterator.hasNext();) {
            Class<? extends Processor> c = (Class<? extends Processor>) iterator.next();
            Constructor<? extends Processor> constructor = c.getConstructor();
            Processor p = constructor.newInstance();
            mapping.put(p.getProcessedClass(), p);
        }
    }

    public <T> Processor<T> getProcessor(T obj) {
        return (Processor<T>) mapping.get(obj.getClass());
    }
}

public class Main {

    public static void main(String[] args)
            throws Exception {
        Adapter adapter = new Adapter();

        A a = new A();

        adapter.getProcessor(a).process(a);

        B b = new B();

        adapter.getProcessor(b).process(b);
    }

}

Result:

14:01:37.640 [main] INFO  org.reflections.Reflections - Reflections took 375 ms to scan 4 urls, producing 222 keys and 919 values 
Processing object A
Processing object B
nanda
+1  A: 

You could let the classes itself return the processor

interface Widget {
  Processor getProcessor();
}
interface Processor {
  void process(Widget w);
}
abstract class WidgetA implements Widget {
   Processor getProcessor() { 
      return new Processor() { 
         void process(Widget w) {// do magic default process stuff}
      }; 
   }
}
class WidgetB extends WidgetA {
   // uses default processor
}
class WidgetC extends WidgetA {
   Processor getProcessor() { 
      return new Processor() { 
         void process(Widget w) {// do magic widget C process stuff}
      }; 
   }
}

However for the different skin story, Perhaps it would then be better to create a processor factory that returns the right processor depending on widget, for the different skins you could then create ProcessorFactory that depends on which skin is used

interface ProcessorFactory {
  Processor getWidgetAProcessor();
   ....
}



 abstract class WidgetA implements Widget {
   Processor getProcessor() { 
      return factory.getWidgetAProccesor();
   }

   void setProcessorFactory(ProcessorFactory pf) {
       this.factory = pf;  // move method signature also to interface
   }
 }

note: this is only an idea, certainly not the best solution i think

Redlab
+1  A: 

How about create Processor implementation for each Object, then we register them into CompositeProcessor, e.g.

public class ProcessorB implements Processor
{
    public void process(A input) { // do something here for B. }
}
public class ProcessorC implements Processor
{
    public void process(A input) { // do something here for C}
}
// add more processors if needed

public class CompositeProcessor implements Processor
{
     private Map<Class,Processor> processors;
     public CompositeProcessor(Map<Class,Processor> processors)
     {
          this.processors=processors;
     }
     public void process(A input) 
     { 
          for (Map.Entry<Class<?>,Processor> entry : processors.entries())
          {
               if (entry.getKey().isAssignableFrom(input.getClass())
               {
                   entry.getValue().process(input);
                   return;
               }
          }
          // do default processing here
     }
}

Now use CompositeProcessor in the Runner class.

Note: I did not compile the code above, just typed in this editor, hence probably there are some errors, but you get idea :).

Some advantages are: - the processor is separated from the class it processes (e.g. A and ProcessorA are separated). - There could be more than 1 processors of the given object - The mapping of processors can be changed at runtime

Bramandia R.