【问题标题】:How to composite using-by objects (real world example)如何合成 using-by 对象(真实示例)
【发布时间】:2021-09-27 02:04:56
【问题描述】:

嘿,我对一个真实的单词示例有疑问。 它与我的另外两个有关,但在这里没有真正回答问题:

https://softwareengineering.stackexchange.com/questions/423392/no-trivial-god-class-refactoring

https://softwareengineering.stackexchange.com/questions/425113/different-composition-techniques-from-the-perspective-of-the-client

假设我们有一个带有switchOn()switchOff() 方法的开关。 开关包含在其他一些结构中,例如switch-bag,我可以从中拔出开关。 这可以看作是一个现成的系统。

现在我想介绍在一定时间后自动打开这些开关的可能性:A time switch

time switch 现在使用 "normal" switchnormal switch 不必了解time switch 的任何信息。

但是现在客户可以从switch-bag 中提取normal switch,现在他还想访问与这些normal switch 相关的time-switch,也许是为了配置一个新的时间。

这是我的问题,客户如何才能到达time-switch

有几种可能:

  • 我将normal switch 类重构为第三类,其中 normal-switchtime switch 捆绑在其中。但为此, 我破坏了其他一些仍然使用normal switch的客户端代码,但是 现在从 switch bag 中取出一个“Combinator”-Class/Object。
  • 我不会更改 normal switch 类的任何内容。客户如果他 想要访问time switch 必须询问与time switch 相关的地图。 (我认为这种方法是经典的 关系编程风格,如 sql 关系数据库及其 不再是真正的面向对象风格)
  • 我扩展了normal switch:这里我也有不同的选择:
    • 我将其更改为一个大外观,它将调用委托给 normal-switchtime switch (类似于我的第一个解决方案 组合器,但这里有一个门面,不会破坏一些现有的 客户端代码)
    • 我扩展了normal switch 让现有的normal switch 代码 原封不动,并介绍了一个组件持有人。进入这个组件 持有人我注入time switch。所以我有这些方法: switchOn();switchOff();getComponent("timeSwitch")。但是这些 方法感觉就像一个实体组件系统 (https://medium.com/ingeniouslysimple/entities-components-and-systems-89c31464240d) 但这仍然是面向对象的编程吗?

我认为最后一种解决方案是最好的,因为它最灵活。

但是您认为哪种方法最好,也许是我在这里没有提到的一些方法?

编辑: 您还必须在这里知道一件事:time switchnormal switch 的一个扩展。其中之一。所以我当然想向normal switch添加更多不同的东西XYZ开关/行为扩展

【问题讨论】:

  • 这家伙会说要避免使用继承(扩展),因为你无法预测你想用你的开关做什么的未来。 youtube.com/watch?v=wfMtDGfHWpA也就是说,我觉得你的问题不会有答案,因为不够集中,而且没有代码。
  • 让事情尽可能简单。
  • @Fuhrmanator 它与继承无关(是的,我的问题中的扩展这个词可能会产生误导;但它更像是我通过在其中添加更多代码来扩展它^^,例如我添加了一些列表到正常开关,因为我可以将时间开关保存为相关组件(实体组件......),这样我以后可以轻松地从正常开关中获得时间开关,而不会中断电流客户端代码)

标签: oop design-patterns architecture composite


【解决方案1】:

更新:完全重写了答案(因此第一条评论不再有意义)。

总结一下:

  • SwitchBag 提供对开关列表/集合的访问。
  • 开关具有 on() 和 off() 等方法。
  • 您希望扩展至少一些开关的行为,这些开关可以根据时间的流逝等自行处理。
  • 客户端(例如 UI)需要访问开关类。

你让 cmets 喜欢

现在他也想去与这些正常的时间开关有关 切换

这表明你每个都有一个,等等 - 这比它需要的要复杂得多。这里有一些可供考虑的选项 - 您的一些选项正朝着正确的方向前进。

选项 A:一种开关

这假设解决方案设计和功能驱动程序不会促使您创建庞大且过于复杂的开关。例如,假设您的某些交换机需要在一段时间后执行某些操作,而其他交换机则不需要。这样的差异不一定足以构成单独的课程。

例如您可以实现一个与时间相关的属性,如Duration,如果Duration > 0,则应用时间逻辑并执行;

我在这里假设任何客户端都可以通过 SwitchBag 访问任何交换机。

这是我要开始的选项,因为它很简单并且仍然允许大量的功能范围。

选项 B:智能开关袋、哑开关

我不确定我是否喜欢这个选项的味道,因为它紧密耦合了 SwitchBag 和 Switch 类,但它可能很有用。

  • 尽可能让 switch 类保持沉默。
  • SwitchBag 了解开关,它控制对它们的访问(以及它们的属性/方法)。使用类结构和访问修饰符来控制它。
  • SwitchBag 可以根据需要决定根据时间对交换机进行处理。

在这种方法中,开关主要是属性,有点像 SwitchBags 个人数据库,只是它在运行时基于对象是流动的。

注意 - 您仍然可以在开关上设置事件。

选项 C:接口

创建一个基本开关。创建旨在应用于交换机类的接口,并根据需要扩展它们。例如:

interface ITimeBehaviour{
  double InitialDuration
  double TimeUntilChange
}

在运行时,您可以查看给定的开关实例是否实现了接口并做出相应的响应。但是,虽然您可以这样做,但根据我对您的问题的了解,我不确定为什么您会这样做。

其他想法

  • 您的 cmets 表明您已经对继承和方法等 OO 概念进行了很多思考,但我没有看到您考虑过异步编程技术的证据 - 例如使用事件。如果您对此一无所知,请进行一些研究并加快速度,然后看看这是否能为您的问题提供一个优雅的解决方案。

  • 设计模式 - 你熟悉设计模式的概念吗?如果你不是,一定要研究一下。网上有大量优质内容,其中描述了可能已经解决了您的问题的根本问题的模式。

【讨论】:

  • 是的,没错,你写的 -> 我们来自一个普通的开关,它不需要知道他们相关的时间开关的任何事情;所以在这种情况下,我必须遍历所有时间开关,或者更好的是我有一个地图,其中保存了关系,但这感觉更像是一个关系数据映射,而不是像那样面向对象
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多