【问题标题】:Brain fail in understanding design patterns for designing a Real Time application大脑无法理解设计实时应用程序的设计模式
【发布时间】:2011-01-21 11:57:05
【问题描述】:

我为自己设定了实现实时 MIDI 应用程序的任务。像我迄今为止编写的所有其他软件一样,我从编码开始。我实现了一个微型 GUI (GTK2) 应用程序,它可以控制Jack Audio Connection Kit 及其客户端的传输状态。

我以前从未写过实时应用程序,也只写过一个多线程程序。这两个细节结合起来使这对我来说是一个巨大的挑战,因为我迄今为止编写的所有软件都不需要我先设计它。我只是偶尔需要笔和纸来解决问题。

然而,这个项目不会让我继续编码。但我对软件设计几乎一无所知,我是自学成才(在 1990 年代中期打折的 2 年计算机学习课程)。我总是循序渐进地工作,让一些东西发挥作用,然后在它的基础上进行建设。

在我的研究过程中,我遇到了模型视图控制器模式,但我发现很难不去考虑细节,并且找不到任何基础来构建而不发现导致一切崩溃的问题。

我需要建议才能越过这个障碍。我需要停止寻找分散我思路的干扰。这是干扰之一。我如何越过这个障碍?

【问题讨论】:

  • 虽然设计应该与语言无关,但我认为有关您将从事的工作的更多细节可能会有所帮助。这是否面向对象?您确定 MVC 适用于您的具体问题吗?
  • @p.marino:目前我已经开始使用 C,因为我的 C++ 有点生疏(而且从来没有那么好)。我确实倾向于以模块化的方式编写 C。但我也可以切换到 C++ 以利用它的一些类特性,但通常使用更 C 风格的方法。
  • @p.marino:我不确定 MVC 是否适用。这也是问题的一部分,当您不熟悉设计模式或问题时如何评估它们?这听起来很荒谬,我晚上正在尝试!
  • 当我说使用 C++ 是一种 C 风格的方法时,我的意思是:使用类而不是结构,并使用构造函数/析构函数和类方法。 C 方法意味着我将使用指针而不是引用,倾向于避免复制构造函数和运算符重载。
  • 模式(恕我直言)主要是一种交流工具:如果你想向同事解释你在做什么,或者问我们你所做的是否正确,拥有共同语言会有很大帮助。在您的情况下,模式不一定有任何好处:您的问题(根据您的描述)是如何进行设计。这可能会带你自己“重新发现”MVC(或其他模式),也许你会让别人告诉你“嘿,这只是飞轮”或“伙计,你在描述 MVC”,但这不是重点,为你,此刻。

标签: design-patterns real-time midi jack


【解决方案1】:

已经为这个问题写的答案很好,但没有一个提到实时软件开发中最独特的部分:实时技术要求。

您需要准确了解您的软件需要的响应速度、可能占用的内存量、启动速度以及可执行文件的大小。如果您使用的是普通 PC,内存要求可能对您来说并不那么重要,但无论您的目标平台是什么,运行时速度要求都很重要。

如果您的高级技术要求“足够好让用户满意”,那么您只需担心低级技术要求 - 基本上,您的目标计算机、目标操作系统和您的第三方库可以处理。

听起来您已经编写了一些低级代码。我建议编写其余的硬件/操作系统/库接口代码,并为每个部分计时,无论是错误情况还是快乐路径。这将使您更好地了解您的代码应如何处理其每个接口。 (例如:这个实用程序调用的超时时间足以让我的应用程序备份!我最好在调用它之前看看我是否可以缩短超时时间或进行一些更好的错误检查!)

最后,大多数实时软件都写成这样的循环:

while( program_running )
{
  // This period needs to be long enough for you to do your work
  //  but short enough that your user doesn't think your program
  //  is choppy. Anything better than 50 Hz is usually good enough
  //  for an application with a human interface.
  wait_for_short_period() 
  check_interfaces_for_new_data()
  update_model() // or state machine
  update_outbound_interface() // the speaker, monitor, whatever
}

这有一些变化(定期回调而不是等待),但这是一般的想法。

【讨论】:

  • 有趣的答案。自从我提出问题以来,我发现了更多信息。目标平台是 Linux - 由于应用程序将使用 JACK,Linux 内核将/应该是一个完整的实时抢占补丁内核(Ingo Molnár RT 补丁)。 RT 线程由 JACK 提供 - 应用程序为 JACK 提供回调。回调不应调用任何阻塞系统调用:文件 i/o、gui 代码、malloc/free、printf 等。还建议使用恒定的运行时间。所以时间段是由 JACK 设置的,如果 JACK 说有工作要做,我的应用最好去做!
  • 你去吧。牢记这些要求,并在适当的时期(自动、每周、每月,具体取决于您的需要)根据您的要求检查您的绩效。如果没有文件 i/o、gui 或屏幕 i/o,调试您的应用程序可能是一项挑战。通常,实时代码是在模拟其目标环​​境的环境中开发和调试的。如果您有类似的东西,请使用它。如果没有,您可能需要制定自己的解决方案,以与您的目标非常相似的方式将测试用例推送到您的代码中。
  • 我列出的限制仅适用于我的应用程序提供给 JACK 以实时使用的回调。我的应用程序的其余部分可以做任何它喜欢做的事情;-)
【解决方案2】:

在非常广泛的术语中,“软件设计”是您将手头的问题分解为一系列模块的过程,并指定每个模块的职责是什么,以及每个模块应如何与其他模块通信(如果在全部)。

有多种方法可以继续此活动。考虑到这是您的第一次尝试,请尽量保持简单:拿一些纸和一支笔。

第一步:写下新应用程序必须能够执行的任务列表。 在此之后,尝试将您认为在逻辑上属于同一组的不同任务分组。

为每个子集找到一个名称,将其写在空白纸上(一个用于子集)并更详细地描述模块的功能,包括它应该处理和/或与其他人交换的数据类型。每一个都是“模块设计论文”

在另一张空白纸上为每个子集画一个框,用正确的名称标记它,然后尝试从一个框到另一个框绘制箭头,每个箭头都应该有一个名称并代表您的一个模块调用另一个。让我们将此模块称为“界面设计论文”。

仔细检查您的模块描述以及它们应该提供给其他模块的接口,看看这是否需要更改原始任务列表以及这如何影响它们管理的数据。

如果模块对您来说太复杂/太大,可以迭代地细分它们。如果你把一个模块拆分成多个子模块,就再画一张界面设计纸,记住,子模块的总和应该能够完成你最初为你的模块设想的所有任务,并且能够回答其余模块的请求系统。

请参阅CRC cards 了解更多详情。

【讨论】:

  • +1 很好的解释。也许您可以添加 TDD 和用户故事。
  • 任务列表说明了我遇到的问题类型。一方面,有用户将要承担和体验的任务,另一方面,我知道作为程序员需要完成的任务才能实现这种用户体验。我很难将两者分开,或者换句话说,难以保持描述这些任务的抽象级别(如果这有意义的话?)。
  • 当然有些是用户执行的......但用户必须通过从菜单中选择或按下按钮来执行这些......并且按钮必须调用界面到其中之一你的模块。当我说“界面”时,我并没有关注 GUI,而是各种模块可以为彼此做些什么。他们为整个应用程序提供的“服务”。
  • @Lieven:我不想让事情变得太复杂。此外,它的定义如此广泛,以至于我可以用结构化分析链接替换 ​​CRC 卡,它仍然是相关的。换句话说,基本设计原则早在 TDD 和用户故事之前就已经使用了,对于 OP,我认为这应该已经是一种改进。
  • 我听取了您的建议 - 根据您提到的 CRC 卡大致遵循一个流程。它确实有帮助,也提出了一些我没有想到的考虑。一开始,我仍在尝试从 MVC 设计的角度进行思考。原来我误解了模式 - 模型是数据结构(不是 jack_process 回调),jack_process 回调也可以被认为是一个视图。见:lalists.stanford.edu/lad/2010/02/0293.html
【解决方案3】:

一种方法是与熟悉设计模式和设计软件的人讨论您的要求并非常粗暴地设计出一个设计。在此过程中,您可以讨论应用设计模式的概念。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多