【问题标题】:Creating child class based on class content根据班级内容创建子班级
【发布时间】:2022-01-14 12:27:57
【问题描述】:

我有一个这样的类结构:

                        LineTemplate (abstract)
                        /                    \
                LineOut (abstract)        LineIn (final)
                /                \
LineOutTransfers (final)     LineOutSells (final)

LineOutLineIn 都应该从文件中读取一行,根据数据库检查其内容并运行多个查询。

然而,

LineOut 包含两个略有不同的变体,这取决于行的内容。由于 LineOutTransfersLineOutSells 在调用它们的方法时执行不同的操作,我决定继承它们并将它们视为子类。

我在LineTemplate中创建了一个public static LineTemplate __init()方法来判断它是LineOut还是LineIn em> 类并根据外部条件返回正确的类型,我想实现一个类似的方法来确定 LineOut 子类的正确类型。

由于 LineOut 子项依赖于行内容,但是,我被困在这一点上。该类应读取该行,然后将其自身转换为正确的孩子,然后执行检查。但这是不可能的,因为我不能将父类转换为子类,如果它还不是那种类型(多态)。

我还考虑过读取 LineOut__init() 方法中的所有行,然后将变量作为参数传递给它的子构造函数,但是因为有一堆要读取的变量,因为它在 LineIn 中的处理方式不同,所以在我看来这是一种不好的做法。

有什么想法吗?提前致谢。

【问题讨论】:

  • 在我看来,继承在这里不是正确的设计,但它的描述过于模糊,无法做出明智的判断。
  • @daniu 我确实想过一个简单的布尔标志,但是两个孩子的方法差异太大了......你建议什么?

标签: java inheritance parent-child multiple-inheritance


【解决方案1】:

优先组合而不是继承,所以不是

abstract class LineOut {
  public void consume(Line l) {
    // ...
    subclassConsume(l);
    // ...
  }
  protected abstract void subclassConsume(Line l);
}
// and
class LineOutTransfers extends LineOut {
  protected abstract void subclassConsume(Line l) { ... }
}
class LineOutSells extends LineOut {
  protected abstract void subclassConsume(Line l) { ... }
}

你应该这样做

abstract class LineOut {
  private TransferLineHandler transferHandler;
  private SellsLineHandler sellsHandler;
  public void consume(Line l) {
    // ...
    if (isTransfer(l)) {
      transferHandler.consume(l);
    } else {
      sellsHandler.consume(l);
    }
    // ...
  }
  protected abstract void subclassConsume(Line l);
}
// with
class TransferLineHandler {
  public consume(l) { // stuff from LineOutTransfers }
}
class SellsLineHandler {
  public consume(l) { // stuff from LineOutSells }
}

这完全消除了“动态子类化”问题,并使代码更具可测试性。

【讨论】:

  • 该死的太聪明了!谢谢你。我猜 TransferLineHandlerTransferLineHandler 中的 consume() 应该是 static 的,不是吗?
  • @Shish 最好不要。我确实将每个处理程序添加为成员,您需要在某处实例化它们。当您调用 consume 方法时,您可能只能拥有执行此操作所需的所有数据,在这种情况下,您不需要成员。
【解决方案2】:

您能否向LineOut 添加一个convertWithContext(SomeClassRepresentingContext ctx) 方法,该方法将返回一个新的LineOut,它将是LineOut 的正确子类?

另一种方法是使用工厂方法并为其提供行内容和上下文。类似的东西

LineOutFactory.instance().constructLineOut(String line, SomeClassRepresentingContext ctx);

在 Java 中,一旦创建类,您就无法更改其类型,您只能根据现有类的内容和可能的外部上下文构建新类。

【讨论】:

  • 听起来不错!但是我应该在那个方法中写什么?我必须一个一个地传递每个变量吗?
  • 你需要足够的代码来构造对象。不知道逐个传递每个变量是什么意思。调用构造函数时,构造函数使用的所有变量都必须可用。如果使用子类很尴尬,那么使用继承的另一个选择是使用接口。如果没有更多信息,很难知道最佳解决方案。
【解决方案3】:

也许工厂方法对这种情况有用:https://refactoring.guru/design-patterns/factory-method

【讨论】:

  • 阅读它...但它没有帮助!创建类后,我需要能够选择类类型。
猜你喜欢
  • 2019-04-26
  • 1970-01-01
  • 2020-02-25
  • 1970-01-01
  • 2020-03-15
  • 1970-01-01
  • 2011-08-09
  • 1970-01-01
  • 2012-09-06
相关资源
最近更新 更多