哪种设计模式允许基于运行时类型抽象功能?

时间:2010-07-14 10:33:56

标签: java design-patterns

我有一个抽象类A和它的几个实现。我希望通过添加更多实现来逐步发展。

我还有一个接口,可以在上面的类层次结构的实例上执行某些操作(例如打印它们)。

我希望接口的实现为A的某些子类提供一些特殊功能,为其余子类提供默认功能。

我希望这个例子澄清事情:

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);
    }

}

该示例打印“默认处理”。问题是要根据接口方法的编译时类型选择要执行的方法。是否有一种方法(或设计模式)使该程序打印“特殊处理”而不在第14行添加

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

每个需要特殊处理的课程?

我查看了visitor模式,但它似乎不是一个改进,因为我不想用A的每个子类的方法“污染”Processor接口,因为A的更多子类将加入。

换句话说,我希望接口的实现:

  • 为A
  • 的特定子类提供方法的自定义实现
  • 为将来添加的类提供默认实现
  • 避免列出大型if-then-else列表中的所有类

谢谢!

6 个答案:

答案 0 :(得分:4)

将代码移动到变化的类型并使用多态。请参阅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);
    }
}

答案 1 :(得分:3)

如果你创建一个接受你想要处理的对象的适配器并返回该对象的处理器呢?

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

代码示例:

class Adapter {

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

}

答案 2 :(得分:1)

您可以让类本身返回处理器

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}
      }; 
   }
}

然而,对于不同的皮肤故事,也许最好创建一个处理器工厂,根据小部件返回正确的处理器,然后根据不同的皮肤创建依赖于使用哪个皮肤的ProcessorFactory

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
   }
 }

注意:这只是一个想法,当然不是我认为最好的解决方案

答案 3 :(得分:1)

如何为每个Object创建Processor实现,然后将它们注册到CompositeProcessor,例如

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
     }
}

现在在Runner类中使用CompositeProcessor。

注意:我没有编译上面的代码,只是在这个编辑器中键入,因此可能有一些错误,但你明白了:)。

一些优点是: - 处理器与它处理的类分开(例如A和ProcessorA分开)。 - 给定对象可能有多个处理器 - 处理器的映射可以在运行时更改

答案 4 :(得分:0)

这是使用Adapter的进一步改进。此解决方案需要来自:http://code.google.com/p/reflections/

的思考库

优势:

  • 否则使用instanceof
  • 无配置

缺点:

  • 需要思考库
  • 开头可能很慢

就是这样:

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);
    }

}

结果:

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

答案 5 :(得分:0)

模板方法。

基类实现默认行为,派生类实现特定行为。

Class BaseWithTemplateMethod {
  void process() {
    // Default behavior goes here
  }
}

Class DerivedWithSpecific extends BaseWithTemplate {
  @override
  void process() {
    // Specific behavior goes here
  }
}

您可以对此主题进行多种变体处理,例如将行为封装在另一个类中,在运行时配置实例以确定它们使用哪种特定行为,而不是使用组合。这在没有多重继承的Java和其他语言中特别有用。