【问题标题】:A Software Design Issue: The Router Class [closed]软件设计问题:路由器类[关闭]
【发布时间】:2009-06-18 22:40:25
【问题描述】:

在子系统设计中,我有时会看到软件设计有一个只有一个功能的高级类:它将使用该类的客户端的调用路由到客户端想要使用的另一个特定类。但是,它本身没有任何功能。以这种情况为例:

假设保龄球馆子系统中有五个类别:球道、球道、保龄球、控制台和得分。每当子系统外部的客户端想要向用户显示任何数据时,它只会与控制台(路由器)通信,控制台会调用它所拥有的任何类来获取客户端请求的数据(例如分数:客户端调用控制台用getScore(),调用Lane的getScore(),调用Bowler的getScore())。

我知道这是一个糟糕的设计决定,但我想听听真实世界的示例,这些示例说明您发现使用此路由器类(也可以称为“中间人”)的后果。随着您正在开发的系统不断发展,您遇到了哪些问题?您会提出什么论据来说服软件设计人员避免使用路由器类?

【问题讨论】:

标签: oop


【解决方案1】:

我认为在某些设计中,路由器是首选的设计模式,例如在 MVC 框架中为 URL 委派处理程序。在这种情况下,它真的很有帮助,因为它在客户“看到”的内容和它背后的实际逻辑之间提供了非常清晰的分离。

【讨论】:

  • 参见上面关于“高内聚”违规的评论。例如,如果我是 LaneView,是 Lane 的 GUI,为什么我要与控制台交谈以获取 LaneView 数据?这没有意义,因为我正在显示车道数据。 (也许这会澄清我在软件设计中所说的陷阱)。
  • 第二句应该是Lane数据,不是LaneView数据。
  • 我同意,在大多数情况下,这种模式没有意义。但在 MVC 的情况下,它非常有意义,因为在某些时候必须委托处理 URL 的东西。因此,真正有意义的仅有的两种设计是一个处理所有请求的巨大单片代码,或者一个配置为根据 URL 将请求传递到其他代码段的小型“路由器”。这种间接级别还允许您“热交换”功能,同时为您的用户提供一致的界面。
【解决方案2】:

每当子系统外的客户端想要向用户显示任何数据时,它只会与控制台(路由器)进行通信,控制台会调用它拥有的任何类来获取客户端请求的数据

这听起来像Facade pattern

至于中间人,在下面的例子中,车道不会是罪魁祸首吗?

以分数为例:客户端用getScore()调用控制台,调用Lane的getScore(),调用Bowler的getScore())

为了子系统外的客户的利益而简化子系统的接口可以被认为是好的设计。

【讨论】:

  • 不一定。看到糟糕的代码气味:中间人。另请参阅我在设计模式类的笔记中的摘录:“第一个误用来自于模式的简单化应用程序,它只是位于应用程序和子系统之间的“中间人”。外观中的大多数行为只是传递调用子系统中单个操作的操作。这不是子系统提供的更高级别的接口,并且并没有真正使它更易于使用。如果没有更高级别的接口,Facade 的意图的一个方面是不见了。”
【解决方案3】:

外观模式和Mediator 模式执行与您所描述的任务类似的任务。您使用中间人绰号意味着中介者模式优于外观模式,因为中间人负责在两个实体之间进行协商,而两个实体都不需要知道如何与另一个实体进行通信的细节。

您可以使用这两种模式中的任何一种来减少客户端类的耦合,这需要使用 Mediator 或 Facade 所屏蔽的系统。在外观模式的情况下,其目的是提供一种方便的方式来连接类系统。对于中介者模式,目的是从客户端抽象出执行复杂任务所需的步骤。

【讨论】:

    【解决方案4】:

    我不知道路由方法调用总是是个坏主意。

    【讨论】:

    • 路由器违反了设计原则:高内聚,因为您不是直接与您的“朋友”交谈,而是通过某事(甚至可能不止一件事)进行交谈。 (将这种情况想象为您只能通过仅路由的高级接口访问特定的数据集)。
    • @jds2501 您似乎已经拒绝了这里的所有建议答案。那么路由器类的模式是什么?
    【解决方案5】:

    您似乎只是遇到了与任何额外的抽象层相关的问题 - 抽象可能会中断,或者如果对底层的某些内容进行了更改,它可能会出现行为异常。

    我从来没有见过任何调用超过几层的东西,但我只是想象添加额外的调用会使跟踪信息所采用的路径变得更加困难,并使故障排除更加困难。

    然而,一个潜在的问题是,如果每一层都实现了自己的错误处理或重试过程,那么在每一层上微不足道的事情就会成为一个整体。例如,如果 Lane 两次尝试检查投球手的得分,而桌子尝试 3 次检查得分,则投球手未能返回得分将导致 6 次查询。在投球手上添加一个 30 秒的暂停时间,您会突然等待 3 分钟,而原本应该需要 30 秒的时间。

    OldNewThing 有一篇文章介绍了 Windows 操作系统中的一个示例,以及它导致的问题,但现在我似乎找不到它。

    【讨论】:

      【解决方案6】:

      我认为 ASP.NET MVC 和 MVP 模式都利用了这种类型的概念,您最终得到的只是处理从一端到另一端或代表较低层到较高层执行的逻辑。这无疑使测试更容易执行,因此这本身就是一个主要的好处。这种类型的模式确实会创建一些手动或繁琐的工作,因为您可以单击一个按钮并让它执行一项任务而不是单击该按钮,让某些东西拦截该单击,然后调用一些执行某些工作的服务管理类。但是在保持代码干净和可读性方面,通常越多的分离越好。

      如果您不是测试人员或不太关心模式,那么请考虑另一种格式。您有一个将用户带到页面的链接。此链接分散在您的网站各处,因为目的地非常重要或经常使用。目的地变了。这可能是查找和替换操作...或者您可以插入一个 RedirectService (随意调用它),当有人单击链接时会进行更改并将点击器定向到正确的位置。这允许在一个位置定义一次位置,因此更改一次。经常查找和替换会改变原本不应该改变的东西!

      不管你怎么看……关注点分离是个好主意。 UI 是一个问题。活动的控制者是另一个问题。活动本身是另一个问题!

      【讨论】:

      • 查看子系统示例,其中 LaneView 与控制台对话以获取车道数据,而不是 LaneView 与车道对话以获取车道数据。如果高级接口简化了子系统的功能,我同意高级接口的抽象对于子系统来说是一个不错的选择。一个简单的路由调用(字面意思是高级接口中的一个函数调用)没有提供抽象的好处,并且错过了外观模式意图的一个方面。
      猜你喜欢
      • 2013-04-14
      • 1970-01-01
      • 2011-04-04
      • 2013-01-12
      • 1970-01-01
      • 1970-01-01
      • 2013-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多