0

我有以下设置:

class Base {};
class ImplA extends Base {};
class ImplB extends Base {};
class ImplC extends Base {};

Base baseFactory(int type) {
    switch(type) {
    case 0:
        return new ImplA();
    case 1:
        return new ImplB();
    case 2:
        return new ImplC();
}

Base a = baseFactory(0);
Base b = baseFactory(1);
Base c = baseFactory(2);


List<Base> list = new ArrayList<Base>();

list.add(a);
list.add(b);
list.add(c);

// Somewhere else I have:
interface BaseHandler {
    process(ImplA a);
    process(ImplB b);
    process(ImplC c);
};

现在,我希望能够做的事情是:

class Processor {

BaseHandler bh;

Processor(BaseHandler bh) {
    this.bh = b;
}

void processList(List<Base> list) {

    for (Base x : list) {
        bh.process(x);
    }
}

然后让用户实现 BaseHandler 并能够构造一个 Processor 来对 Base 列表中的每个元素进行操作。

但是,这不起作用,因为process(Base)没有定义。只添加 3 个 if 语句似乎很简单,但我已经有了一个类似 switch 的结构来构建扩展 Base 的类的实例。似乎没有必要一遍又一遍地重复这一点。有没有办法实现这个想法,而无需编写中间步骤来确定列表中每个 Base 的运行时类并调用适当的方法(实际上是另一个 switch 案例——但它会是 if 的)?

我认为一个解决方法是让每个 Base 都有一个process需要由 Impl 类实现的抽象方法。但是,这在我的情况下是不可接受的,因为用户不会实现 Impl 类。基本上,我需要process是一个用户定义的回调。process此外,成为 Impl 或 Base 类的成员没有任何意义,因为它们没有任何关系。这是一个单独的回调,需要动态响应调用它的类型。并且类型总是保证是 Base 的子类。

4

3 回答 3

6

您确实需要您描述的“中间步骤”,但它不需要是if陈述。您正在寻找的是使用访问者模式的双重调度。基本上你的Base班级会有一个方法:

void accept(BaseHandler handler);

并且每个子类都将其实现为:

handler.process(this);

wherethis将在编译时解析为每个子类中的正确类型。

于 2012-07-07T16:05:20.687 回答
2

您正在寻找的是访问者模式。您在 上放置了一个抽象方法Base,但它所做的只是在以下位置调用适当的方法BaseHandler

public interface Base {
    void acceptHandler(BaseHandler handler);
}

然后你的具体实现覆盖acceptHandler并调用正确的重载。

public class ImplA implements Base {
    public void acceptHandler(BaseHandler handler) {
        handler.process(this);
    }
}

在这一点上,重载没有太大的价值,你最好给你的方法提供描述性的名称。

于 2012-07-07T16:07:17.740 回答
2

听起来您想要的是这里的访问者模式:

public interface BaseVisitor {
  void caseA(ImplA a);
  void caseB(ImplB b);
  void caseC(ImplC c);
}

public class MyVisitor implements BaseVisitor {
  void visit(List<Base> bases) {
    for (Base b : bases) {
      b.accept(this);
    }
  }
  public void caseA(ImplA a) { // ... }
  public void caseB(ImplB b) { // ... }
  public void caseC(ImplC c) { // ... }
}

public abstract class Base {
  abstract void accept(BaseVisitor visitor);
}

public class ImplA {
  public void accept(BaseVisitor visitor) {
    visitor.caseA(this);
  }
}
public class ImplB {
  public void accept(BaseVisitor visitor) {
    visitor.caseB(this);
  }
}
public class ImplC {
  public void accept(BaseVisitor visitor) {
    visitor.caseC(this);
  }
}
于 2012-07-07T16:12:19.280 回答