首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从statechart框架中删除依赖项

从statechart框架中删除依赖项
EN

Stack Overflow用户
提问于 2011-09-13 04:30:29
回答 3查看 209关注 0票数 2

我现在正在做的项目有很多问题。这个项目已经有10多年的历史了,它是基于90年代非常流行的商业C++框架之一的,问题在于状态图。该框架提供了相当常见的状态模式实现。每个状态都是一个单独的类,具有进入时的操作,状态中的操作等。有一个开关,根据接收到的事件设置当前状态。

魔鬼隐藏在细节中。这个项目是巨大的。大约是2000 KLOC。状态图确实太多了(我见过使用状态图实现的"for“循环)。更重要的是。框架允许将状态图嵌入到另一个状态图中,因此有许多具有七层甚至更多层嵌套的状态图。因为状态图运行在不同的线程中,并且可以在状态图之间发送事件,所以我们会遇到很多同步问题(以及接口中的大混乱)。

我必须承认,这个问题的规模是巨大的,我不知道如何去触及它。我的第一个想法是尽可能多地从状态图中删除代码,并将其放入单独的类中。然后从statechart中委托这些类来执行一项工作。但结果是我们将有许多独立的函数,这些函数在逻辑上没有任何特定的功能,状态图体系结构中的任何更改都需要更改这些类和函数。

所以我请求帮助:你知道有什么书/文章/魔法工艺品可以帮助我解决这个问题吗?我希望至少将尽可能多的代码从statechart中分离出来,而不引入任何隐藏的依赖关系,并保持分离的代码可维护、可测试和可重用。

如果你有任何建议如何处理这个问题,请让我知道。

EN

回答 3

Stack Overflow用户

发布于 2011-09-13 06:11:11

statechart模式专门用于删除switch语句,因此这听起来像是一种可怕的滥用。此外,状态应该只在异步事件时更改。如果您正在处理一个事件,并且您通过多个状态(或for循环等)进行更改,那么这也是对模式的可怕滥用。

我将从这两点开始,因为它们将解决大部分并发问题,只需修复它们即可。您需要确定的是:

  1. 系统的外部异步事件是什么?这些是唯一应该决定状态转换的事情,而不是在事件处理过程中发生的事情。事件可能导致0或1状态转换。一旦您有了这些状态转换的列表,您就可以重建系统的实际状态。如果您了解UML状态图,这将是在图表程序中绘制状态图的最佳时机,不仅对您自己(尽管它将对您有极大的帮助),而且对将来必须返回该项目的每个人也是如此。
  2. 现在你知道了什么是真正的状态,在代码中列出哪些是不应该的状态。这通常表示某些东西可以“功能分解”。可能所有需要的都是一个单独的函数,而不是每个对象的状态对象。这将大大减少状态对象的开销,并且可以极大地清理代码。
  3. 现在是时候处理您提到的那些可怕的switch语句了。如果它们真的是基于状态的,那么您根本就不需要它们。相反,您应该能够直接调用状态机。

类似于:

代码语言:javascript
复制
myStateMachine->myEvent();

它应该在没有任何开关的情况下工作。但请注意,即使对于那些不能跨异步事件工作的对象,情况也可能是这样的。这也表明您可以在哪里使用继承来获得相同的效果。如果您有:

代码语言:javascript
复制
switch (someTypeIdentifier)
{
case type1:
  doSomething();
  break;

case type2:
  doSomethingElse();
  break;
}

通常,正确的OOP方法是创建两个实际类型Type1和Type2,这两个类型都是从抽象的基类TypeBase派生的,使用一个执行所需操作的虚方法doSomething()。这很有用的原因是因为它意味着您可以“关闭”处理(在Open/Closed原则的含义中),并且仍然可以根据需要通过添加新的派生类型来扩展功能(使其对扩展开放)。这极大地减少了bug,因为它让开发人员摆脱了那些非常丑陋和复杂的switch语句,而是将每个单独的行为封装在单独的类中。

4-现在来解决你的线程问题。标识从多个线程使用的所有对象。列一张清单。现在,这些是如何使用的?它们中的一些是经常一起使用的吗?开始分组吧。这里的目标是找到最适合这些对象的封装级别,将对象分离到控制其自身同步的单个类中,找出对象的实际“事务”的原子级,并创建公开这些有意义的事务的类的方法,并在幕后使用适当的互斥锁、条件变量等进行包装。

你可能会说:“这听起来像是很多工作!为什么要这么做,而不是只写在我身上?”问得好!:)原因其实很简单:如果你要自己做所有的事情,这些都是你应该做的步骤。你应该识别你的状态,你的动态多态性,并获得多线程事务的句柄。但是,如果您从现有代码开始,您也会有所有那些从未记录在案的未言明的业务规则,并且可能会导致各种意外的But。你不必把所有的东西都带过来--如果你怀疑这是一个bug,就和过去使用过系统的人(如果有的话),QA,或者任何可能识别bug的人讨论逻辑,看看是否真的应该继续下去。但是,无论哪种方式,您都需要实际评估错误是什么,否则您可能不会编写实际需要编码的代码。

最后,这是一个手动过程,是软件工程的一部分。有CASE工具可以帮助绘制状态图,甚至可以将它们发布到代码中;有重构工具,比如许多IDE中的重构工具,可以帮助在函数和类之间移动代码;还有类似的工具,可以帮助识别线程需求。然而,这些东西不应该在单个项目中使用。它们需要在你的职业生涯中学习,在多年的工作中学会并更深入地学习,因为它们是软件工程师的一部分。他们不是为你这么做的。你仍然需要知道为什么和怎么做,它们只是帮助你更有效地完成它。

票数 1
EN

Stack Overflow用户

发布于 2011-09-13 05:33:51

在我看来,你最好的选择是(吞下去!)如果它像你说的那样可怕,很可能会从头开始。有什么文档吗?你能开始基于文档构建一些更健全的软件吗?

如果完全重写不是一个选择(在我的经验中从来没有),我会尝试以下一些方法:

  1. 如果你还没有,画一幅整个系统的架构图。勾勒出所有部分应该如何协同工作,这将帮助您将系统分解为可能可管理/可测试的部分。
  2. 您是否有任何类型的要求或测试计划?如果没有,你能不能写一个并开始对已经存在的各种代码/功能块进行单元测试?如果你能做到这一点,你就可以开始重构事物,而不会破坏当前正在运行的任何东西。
  3. 一旦您分解了一些东西,就可以开始将您的单元测试构建到集成测试中,这样就可以将更多的功能整合在一起。

我自己没有读过这些书,但我听说了一些关于这些书的好东西,它们可能会有一些你可以借鉴的建议:

  1. Refactoring: Improving the Design of Existing Code (Object Technology Series).
  2. Working Effectively with Legacy Code (Robert C. Martin)

祝你好运!:-)

票数 0
EN

Stack Overflow用户

发布于 2011-09-14 18:05:00

Statecharts (包括嵌套Statechart)是指定、理解甚至模拟/验证复杂控制流的强大方法。但为了获得好处,您需要在合适的工具中使用statechart模型(我很早就使用Statemate,不确定它是否仍然可用),再加上从图表到代码的可靠映射(Statemate用于生成代码)-然后您就可以忘记状态管理代码(主要是)!在你的情况下,如果你没有模型,我会试着从代码中倒过来一个-正如Ira所说,原始开发人员很有可能以某种形式拥有一个模型,并且随着模型的出现,你可能会发现代码很有意义。如果这真的成功了,你将拥有一个非常好的代码规格/模型,这应该会使将来的代码编辑变得更加容易(即使你不想自动生成代码,并手动维护代码/模型映射(但你需要非常小心!))

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7393620

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档