处理超类型的所有子类型

时间:2012-03-22 09:12:29

标签: java oop design-patterns inheritance

将抽象超类型的不同子类型作为参数处理的最佳方法是什么,例如处理事件时。

情况如下:

超类型:

public interface MySuperInterface {
}

子类型

public class SubclassA implements MySuperInterface {
}

另一个子类型

public class SubclassB implements MySuperInterface {
}

某些类应该能够处理MySuperInterface的任何子类型

public class MySuperHandler {

   public void handle(MySuperInterface mysuper) {
       //do it
   }

}

我的不同方法是

  1. 处理程序方法中的switch / case语句。 (我不喜欢)

  2. 接口中的方法接收(MySuperHandler)以及对此方法的调度 在handle方法中: mysuper.receive(this)(这意味着接口知道处理程序类)

  3. 为MySuperHandler类中的每个子类型添加句柄方法(这不能确保可以处理每个子类型)
  4. 但出于上述原因,我不满足于这些解决方案。

    有没有办法处理这种情况?

    感谢

2 个答案:

答案 0 :(得分:3)

一种方法是使用Visitor Pattern。它看起来像这样:

public interface MySuperInterface {
  <T> T acceptVisitor(MySuperInterfaceVisitor<T>);
}

public interface MySuperInterfaceVisitor<T> {
  T visitA(SubclassA a);
  T visitB(SubclassB a);
}

public class SubclassA implements MySuperInterface {
  <T> T acceptVisitor(MySuperInterfaceVisitor<T> visitor) {
    return visitor.visitA(this);
  }
}

public class SubclassB implements MySuperInterface {
  <T> T acceptVisitor(MySuperInterfaceVisitor<T> visitor) {
    return visitor.visitB(this);
  }
}

public class MySuperHandler implements MySuperInterfaceVisitor<Foo>{
  Foo visitA(SubclassA a) {
    // construct Foo from SubclassA instance
  }

  Foo visitB(SubclassB a) {
    // construct Foo from SubclassB instance
  }
}

这有点像你的#2,除了接口(和子类)不需要知道处理程序。他们只需要了解访客界面。如果您不希望MySuperInterface及其实现了解您的特定处理程序,那么这很好。

BTW,而不是打电话:

myHandler.handle(myImpl);
你打电话给:

myImpl.acceptVisior(myHandler);

如果你想确保每个处理程序都可以处理你的接口的每个实现,但仍然保持实现不知道存在的所有“处理程序”,这种方法很好。

如果添加接口的另一个实现(MySuperInterface),编译器将强制您添加acceptVisitor方法。此方法可以使用现有的visit*方法之一,也可以在访问者界面中添加新方法。如果您执行后者,则必须更新所有访问者(也称为“处理程序”)实现。这确保了可以处理每个子类型。

这种方法比assylias的答案更复杂,只有你想要打破MySuperInterface的实现与你的处理程序代码之间的耦合,或者你有强烈的组织愿望才真正有意义处理程序代码,以便特定类型处理的所有代码都是“在一起”。

访客模式的一个常见用途是以不同方式呈现对象。假设您希望能够将对象转换为PDF或HTML。您可以在界面中使用toHTML和toPDF方法。这种方法的缺点是,现在您的类依赖于您的库来生成HTML和PDF。此外,如果某人后来想要添加新类型的输出,则需要修改这些核心类,这可能是不合需要的。使用访问者模式,只有访问者类需要了解PDF或HTMl库,并且可以添加新访问者而无需修改核心类。 (但同样,添加新的核心类意味着您需要重用现有的visit*方法,或者您必须修改访客实现的所有。)

答案 1 :(得分:2)

你的描述有点模糊但如果你有几个子类,其中一些共享一个共同的“句柄”行为,这可能有用 - 如果你只有2个子类,并且不打算将来有更多,抽象步骤可能是不必要的:

public interface MySuperInterface {
    void handle();
}

public abstract AbstractMySuperInterface {
    public void handle() {
        //implement default behavior
    }
}

public class SubclassA implements MySuperInterface {
    //nothing here, just use default behavior
}

public class SubclassB implements MySuperInterface {
    public void handle() {
        //implement another behavior
    }
}

public class MySuperHandler {

   public void handle(MySuperInterface mysuper) {
       mysuper.handle();
   }
}