【问题标题】:How to avoid instanceof when hiding a field隐藏字段时如何避免instanceof
【发布时间】:2019-10-04 21:09:31
【问题描述】:

我首先要说,我已经阅读了很多关于避免使用 instanceof 的问题,但我真的看不出任何与我们所看到的情况完全相符的问题。不过,如果您确实看到任何解决此特定问题的内容,请告诉我!

我们现在面临一个问题,我们有一个类负责保存有关在特定时间要采取的操作的信息。这些时间可以是一个单一的动作或在一段时间内重复出现。我们有一个字段(动作的持续时间)仅对重复动作有效。我们最初有一个用于时间类型的 Enum 和一个用于持续时间的单独字段,作为单个类的一部分。

class Action {
    long duration;
    Enum timeType;
}

改为:

class Action {
    TimeTypeStrategy timeTypeStrategy;
}

class RecurringTimeTypeStrategy extends TimeTypeStrategy {
    long duration
}

class SingleTimeTypeStrategy extend TimeTypeStrategy {
}

abstract class TimeTypeStrategy {
}

因此,使用此修改后的代码,我们基本上可以说我们甚至只能有一种类型或另一种类型,并且持续时间只能是循环时间类型的属性。然而,这也意味着,每当我们想要让 action(或其他使用 action 的类)根据其循环时间类型来处理它时,它需要在 timeTypeStrategy 字段上调用 ​​instanceof 来实际检索持续时间并执行它需要的任何调度。

一种想法是,可以将决定成为特定时间类型意味着什么的努力转移到策略本身中。感觉它也应该基于名称,但这需要大量更改一些调度代码,并最终打破了在开发这些调度时开发的一些范式。也许这就是我们需要的解决方案,但感觉不应该是唯一的解决方案。

就设计模式而言,有没有更好的方法,不会导致代码异味,允许调用者根据这些字段决定要做什么?

【问题讨论】:

  • 什么代表duration?为什么只有重复的动作有持续时间?执行一次的动作没有持续时间,它只是立即发生?
  • 你可以这样想。归根结底,这背后的原因并不重要,因为我可以将接口更改为 IceCream 并将类更改为 BoringIceCream 和 FancyIceCream,其中 FancyIceCream 将 splashColor 作为字段。这将等同于同一件事,但如果你真的想要,你可以忽略特定领域背后的推理;)
  • 如果您不希望添加 TimeTypeStrategy 的新子类,则可以选择访问者模式。它适用于小型、稳定的类层次结构。
  • 如果 TimeTypeStrategy 确实是一个 Strategy 对象,它应该在内部使用自己的字段,而不是暴露其实现细节(即封装)。与其要求它的数据,不如告诉它对数据做任何需要做的事情。看起来TimeTypeStrategy 只是一个用于保存Action 状态的数据结构。在这种情况下,我会公开它的数据(而不是称之为策略)。

标签: oop inheritance design-patterns


【解决方案1】:

我认为您正在寻找的是访问者设计模式。您可以具有以下类层次结构:

abstract class Action {
   Enum timeType;
   abstract void Accept(IVisitor visitor);
}
class SingleAction extends Action {

   override void Accept(IVisitor visitor) {
      visitor.Visit(this);
  }
}
class RepeatedAction extends Action {
   long duration;

   override void Accept(IVisitor visitor) {
      visitor.Visit(this);
  }
}

然后你可以有一个访问者界面:

interface IVisitor {
  void Visit(SingleAction action);
  void Visit(RepeatedAction action);
}

和访问者实现:

class ActionVisitor implements IVisitor {

  void Visit(SingleAction action) {
    // Execute the action
  }

  void Visit(RepeatedAction action) {
    // Here you can access action.duration and schedule the action
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-14
    • 1970-01-01
    • 2019-07-10
    • 2012-04-18
    • 2022-11-15
    • 1970-01-01
    • 2021-10-23
    相关资源
    最近更新 更多