16

我很困惑。我正在为我的公司开发一个基于 grails 的内部工具。此工具中的一个组件是一个简单的问题跟踪器(Helpdesk 功能)。我有诸如问题、问题和新功能之类的域对象。这些域类中的每一个都有不同的工作流。

我最初的想法是在域对象中滚动我自己的状态机功能。然后我搜索了状态机引擎和工作流引擎。现在我迷路了。

我想评论一下其他开发人员是如何解决这个问题的。你使用 Drools、Jbpm、Activiti 吗?还是一些更简单的状态机引擎?

我一直在阅读 Drools,Jbpm 的一些文档。他们看起来很好。但似乎我只需要这些库提供的一小部分功能。

我为此使用 Grails,但它当然也很容易使用 Java 库。

4

3 回答 3

17

工作流引擎的主要价值在于它可以通过一些工作流定义 DSL 来定制流。如果您不需要允许用户定义他们自己的任意工作流程,那么您最好只构建自己的工作流程。

此外,工作流引擎通常使您能够定义运行时间很长的业务事务和规则。例如,您可以有一个授权采购订单的工作流程,其中第一步是输入一些关于需要购买什么的信息,然后如果购买价格低于 100 美元,那么您就有相应的规则了,如果是100 美元到 2000 美元之间的直线经理可以,如果更多,则将其发送给其他人以供批准……等等。随着金额的增加或公司的业务政策,这些类型的业务规则多年来往往会发生变化改变。因此,在这些场景中使用工作流引擎是有意义的。可以从工作流引擎中受益的复杂业务交易的其他很好的例子是提出保险索赔,授权贷款或抵押,

规则引擎非常适合从应用程序中提取复杂但不断变化的规则。假设您是一家在线零售商,向美国、加拿大、英国、德国和法国的客户发货。您需要对您在网上商店销售的产品征税,但计算税费的规则因国家/地区和国家/地区的省而异。还有一些东西在一个省免税,在其他省不免税。规则引擎非常适合这些类型的复杂业务规则,只要政府改变其税收政策,这些规则就会发生变化。规则引擎可以给你一个正确的答案,你只需要去规则引擎说我想运行规则#10,这里是规则#10 x,y,z 的输入,你会得到一个答案。

规则引擎和工作流引擎之间的主要区别在于,规则引擎不跟踪事务的状态,它应该是无状态的,只处理您提供的输入。工作流引擎是有状态的,它必须知道工作流的当前状态,并且必须将该状态保存到数据库中。工作流引擎还等待来自外部资源(例如人员或系统)的输入。

根据您对应用程序的描述,我只想编写一些常规类来计算工单的下一个状态,并确保该类有据可查并且易于在几年内更新。我认为规则引擎和工作流引擎对于您的情况来说太过分了,您设置和使用它们所花费的时间比您在 groovy 中编写代码所花费的时间要长得多。如果随着时间的推移你发现你需要规则引擎和工作流引擎的复杂性,我会付出当时而不是现在的代价,保持简单永远是最好的选择。

于 2012-08-17T07:45:31.413 回答
6

我完全同意上述 AMS 的回答,而且我想补充的另一件事是对于大多数情况,使用工作流/规则引擎是过度杀伤和不必要的。KISS(Keep It Simple and Stupid)永远是最好的选择。奥卡姆剃刀也说“不应该不必要地增加实体”

根据我在阿里巴巴的工作经验,大多数配备工作流/规则引擎的应用程序都将维护变成了噩梦,如果您使用简化的impl而不是盲目地选择工作流/规则引擎,那么以后来项目的人会很感激您。

那么,是否有指导何时使用工作流的指南?坦率地说,我不知道,但我知道,当业务逻辑处于流程中时,我们绝对不应该使用工作流。因为如果您愿意,每个业务逻辑都可以在流程图中呈现。

最后,我去年做的最正确的事情之一是重新设计了一个应用程序,用 groovy 脚本替换 Drools,这使得整个系统更加直接、简单和快速。

于 2016-09-21T09:35:54.223 回答
1

“状态机”是常见的设计模式,那么 drools 究竟给了你什么?我个人很看重它的“查询语言”,这就是它发光的原因。您实际上有类似“从堆中查询对象的 SQL”之类的东西。就像 SQL 为您提供“声明式”编程方式一样,当块描述何时以声明方式开始状态转换时,流口水。Drools 被设计为默认状态下是有状态的,并且状态是插入到 drools 会话中的所有事实(POJO)。

让我向您推荐一个简单的用例。您必须为移动电话公司编写应用程序来管理电话:
如果呼叫者 1 正在呼叫被呼叫者 2,并且他当时并不“忙”,请连接它们。
如果被叫忙,请继续呼叫 7 秒,如果被叫在此期间关闭原来的呼叫,则立即接通。
如果被呼叫者在 7 秒内没有断开连接,则使用消息“被呼叫者忙”挂断呼叫者。

简单的三重 if 语句业务方法很快就变成了相当复杂且容易出错的技术任务。我想象背景Timer s' 我在 5 到 10 年前或更新的时候见过很多,比如ScheduledThreadPoolExecutor。如果在预定延迟期间状态发生变化怎么办?你还会等到最后重新计算条件吗?如果这种情况在您的应用程序中相对频繁或时间相对较长,您会将“上下文”保留在内存中吗?您需要跟踪期货并取消它们或使用一些BlockingQueue. 对于这种情况,需要为每个人维护队列,因为每个人都可能被某人呼叫。传统的 OOP 说“您应该将行为附加到您的域实体”。使用这种方法,即使您会使用一些模式来简化(封装)复杂性,您的业务实体也会开始使用相当复杂的技术内容来混乱您的“状态机”开始在多个组件之间传播,如果您会更糟使用“分层样式”,因为您将开始为状态内容生成数据结构,例如Map<Callee, BlockingQueue<Caller>>. 第二天你的客户来找你说,'嘿,我有另一个简单的电话用例给你'。

Drools “自然”地解决了这些问题,因为它使用了完全不同的方法。它跟踪工作内存中的所有对象(它跟踪规则条件),当时间到来时,drools 只能说出您的规则是否有资格执行(rete algorithm back to 1979)。如果状态发生变化,drools 会以有效的方式重新评估每个规则的条件,并从“议程”(执行队列)中放置或删除相应的规则。您插入“工作记忆”的所有对象都形成了任何规则都可以中继的“状态”。您可以在此处找到上述用例的一些图表和测试以及实际的 drools 规则实现

为您的任务使用正确的工具。如果您需要对内部带有 3-5 个字段的 State 对象的实体集合进行循环,请不要在标题中添加“状态机”。如果您确实面临诸如“持续行为变化”或系统中事件之间复杂的因果依赖关系之类的问题,那么 drools 是一个很好的并且经过时间证明的开源rete 算法实现。不要试图使用广告中的所有内容,深入了解细节,了解适合您的需求。

于 2020-01-28T21:44:00.710 回答