使用Delphi为win32应用程序实现动态过程映射


5

Delphi XE,Win32应用程序,SQL Server 2005数据库。

我正在实施质量管理体系。 我有一些预定义的过程映射,以在我的应用程序/系统中应用它们。我被要求拥有所有的交易(我不确定它是否是正确的词)动态,所以无论何时修改过程映射,它都会影响应用程序(当然无需重新编译或任何补丁)

这是一个示例解释更清楚:

假设一个文档控制模块,我们有一个过程图如:

  1. [文档控制器]接收来自承包商
  2. 文档
  3. [文档控制器]与检查表检查该文档
  4. [文档控制器]将文档发送到[项目经理]
  5. [项目经理]应用和操作文档中
  6. [项目经理]文档发送到[文档控制器]
  7. [文档控制器]归档文档。

现在,应用程序应该从数据库中读取其功能的参数。 比方说收到并检查了文档(1和2),然后发送它。一旦按下“保存”按钮,系统应该检查谁应该是本文档的接收者并将文档发送给他/她。 在我们的例子中,接收者是[项目经理]。但是,稍后他们可能决定将过程映射更改为 - “3- [文档控制器]将文档发送到[Project Architect]”。 因此,系统应按照流程图中的定义进行操作。

我想知道什么是实现这样的系统(Delphi XE,win32)的正确方法?

我有一些想法,但不知道这是否是正确的: 对于过程图中我可以定义一种唯一ID的服务每一个过程,我从数据库中读取的服务,并调用它在应用层(有相关参数)。在这种情况下,我不确定每个服务应该是一个dll还是包文件,并且我认为拥有这些数量的库文件是错误的,因为这些服务不会很少!

我希望我能很好地解释我的问题,并且抱歉太长。 请让我知道,如果它不明确。

感谢,
Mahya

+2

我认为这是一个架构问题,而不是一个编码问题,因此不适合Stack Overflow。 06 6月. 112011-06-06 09:45:33

+1

也许相关或有帮助:_“是否有一个”工作流程引擎“实施德尔福?”_(http://stackoverflow.com/questions/3492725/is-there-a-workflow-engine-implementation-for-delphi) 06 6月. 112011-06-06 10:14:33

2

像要应用一些共同规则为您的应用程序执行,从而实现某种形式的质量管理的每一个“业务功能”听起来给我。我将使用“业务功能”来表示可能跨越源代码中的多个技术功能和过程的逻辑操作。

没有定义“正确的方式”,但有些想法比其他想法更好。

使用数据库来存储动态数据显然是一个好主意。例如,您可以将每个业务功能建模为一个单独的实体(每个业务功能具有一个数据库记录)。无论您需要哪些变量来管理每个业务功能的处理,都将确定必要的字段。你一定会需要一个唯一的ID每个人。

没有任何理由将业务函数编码到单独的dll中,但我会将它们放在源代码中的单独单元中,或者可能根据它们的操作类型或某些其他逻辑分组对您的函数进行分组商业。您需要改变调用业务功能的方式。您需要间接调用它们,换句话说,您会调用一个通用的PerformFunction例程,可能会传递一个函数标识符和其他任何适合您的数据结构参数。由于参数在数据库中发生了变化(根据您的示例,将文档发送给谁,项目经理或项目建筑师?),业务功能的操作将会相应地进行修改,只要您已经实施了所有可能的排列组合考虑到每个业务功能的变量数量可能会出现这种情况。我确定文档收件人的电子邮件地址并不是您想到的。以下是一些可能有所帮助的代码。我并不是说这是很好的代码,只是表达了这个想法。

type 
    TFunctionRuntimeParameter = record 
    FunctionID: integer; // this better be unique 
    FunctionName: string; // something intelligible for display purposes 
    ReportToEmail: string; // who to send the end report document 
    AuditLevel: integer; // for example vary the degree of auditing/logging 
    variableABC: TDateTime; // could be a date that influences something 
    end; 

function TMyForm.GetRuntimeParametersFromDB(aFunctionID: integer): TFunctionRuntimeParameters; 
var 
    tempResult: TFunctionRuntimeParameters; 
begin 
    // For brevity I'm going to assume an existing query object connected to your db. 
    qry.SQL.Add('Select * From BusinessFunctions Where Function_ID = :FunctionID'); 
    qry.ParamByName('FunctionID').AsInteger := aFunctionID; 
    qry.Open; 
    tempResult.FunctionID := qry.FieldByName('Function_ID').AsInteger; // don't ask me Y! 
    tempResult.FunctionName := qry.FieldByName('Function_Name').AsString; 
    tempResult.ReportToEmail := qry.FieldByName('Report_To_Email').AsString; 
    tempResult.AuditLevel := qry.FieldByName('Audit_Level').AsInteger; 
    tempResult.variableABC := qry.FieldByName('ABC').AsDateTime; 
    result := tempResult; 
    qry.Close; 
end; 

procedure TMyForm.PerformFunction(aFunctionID: integer; FRP: TFunctionRuntimeParameters); 
var 
    MyReportDocument: TMyReportDocument; 
begin 
    if (FRP.AuditLevel > 0) then 
    // do something special before starting the function 

    case aFunctionID of 
    101: MyReportDocument := DoBusinessFunctionABC; 
    102: MyReportDocument := DoBusinessFunctionDEF; 
    103: MyReportDocument := DoBusinessFunctionXYZ; 
    end; 

    SendReportDocumentByEmailTo(MyReportDocument, FRP.ReportToEmail); 

    if ((Now - FRP.variableABC) > 28) then 
    // perhaps do something special every 4 weeks! 

    if (FRP.AuditLevel > 0) then 
    // do something special after the function has finished 
end; 

procedure TMyForm.btnBusinessFunctionXYZClick(Sender: TObject); 
var 
    FunctionID: integer; 
    FunctionRuntimeParameters: TFunctionRuntimeParameters; // record that mimics db entry 
begin 
    FunctionID := 1234; // or you might prefer an enum 
    FunctionRuntimeParameters := GetFunctionRuntimeParametersFromDB(FunctionID); 
    PerformFunction(FunctionID, FunctionRuntimeParameters); 
end; 

这种方式在数据库中运行参数的变化,应用程序将表现不同,无需重新编译。