0

所以我的应用程序是一个出租车呼叫调度系统,其中操作员通过电话接听电话并将接听的电话分配给司机。在输入呼叫详细信息的“呼叫详细信息”表单上,单击“保存”按钮后,该表单应关闭,应在后台线程中向出租车司机发送电子邮件,并显示主表单,他可以在其中选择下一个呼叫并将其分配给另一个驱动程序。

设计的难点在于它应该是一个队列,这意味着队列中的电子邮件需要等到对正在发送的电子邮件的处理完成。当然,电子邮件发送发生在与 VCL 主线程不同的线程中。

对主线程的唯一响应将是队列中剩余的电子邮件数量,通过从主线程到电子邮件程序线程的函数调用。例如。如果用户试图关闭应用程序,它将询问电子邮件队列类是否有任何电子邮件待处理。

在 Delphi 中,什么样的类设计和构造最能实现这个功能?我确定它有一个或多个 TThreads,但除此之外我迷路了。我本可以开始写一些东西,但我确信它是错误的,我需要把它拆开,在这里发布并根据建议重新开始。这就是为什么我首先在​​这里发布 - 我想要设计技巧。由于我使用的是 Delphi,所以我在这里发布是因为我想要特定于 Delphi 的设计技巧。提前感谢您的任何答案。

注意:我愿意使用 TThread 实现或 OmniThreadLibrary。

我为该课程提供了一个基本模板,答案需要扩展和构建。

unit uEmailQueue;

interface

uses Classes;

type
  TEmailServer = record
    SMTPHost: String;
    SMTPPort: Integer;
    SMTPUseSSL: Boolean;
    SMTPUserName: String;
    SMTPPassword: String;
    SMTPSenderName: String;
  end;

  TEmailMessage = record
    RecipientEmailAddr: String;
    EmailSubject: String;
    EmailMessage: String;
  end;

  TEmailQueue = class(TObject)
  private
    FEmailServer: TEmailServer;
  public
    procedure SendEmail(AEmailMessage: TEmailMessage);
  end;

implementation

{ TEmailQueue }

procedure TEmailQueue.SendEmail(AEmailMessage: TEmailMessage);
begin

end;

end.
4

1 回答 1

1

我建议你设置OTL。

您很可能拥有唯一的 SMTP 服务器,因此只有唯一的邮件发送线程,以防您稍后添加更多通知发送服务器(例如向不同的电话运营商发送 SMS) - 您将添加更多传出“接收器”线程。

我个人会考虑使用管道模式。

目前它看起来主要是过度设计,但它稍后会为您提供自定义和扩展(例如添加比发送电子邮件更多的通知方式,例如流程记录,例如添加“VIP客户/普通客户/阴暗客户/欺诈”启发式)或其他任何东西。

由于管道从一些线程安全的源数据收集/容器开始,要开始处理新请求,您只需要将任务记录放入该队列。

就像是

 var TaxiInQueue: iOmniBlockingCollection;
 ....
 var NewTask: TEmailMessage;
 ...
 TaxiInQueue.Add( TOmniValue.FromRecord(NewTask) );

同样,这将使您能够从单线程 GUI 应用程序(使用单个代理放入新任务)扩展到网络代理(3 层或 WWW-servlet),其中多个线程同时从不同的连接/线程输入新任务。

对主线程的唯一响应是队列中剩余要发送的电子邮件数量

就我个人而言,我会以“双重核算”的方式来做,我会保留两个变量:创建的总任务和完成的总任务。它们可以由主线程中的一个单独的不可见窗口管理(AllocateHWND 并使用 PostMessage 触发增量),或一个单独的工作线程(可能过度工程),或者只是一个带有任何类型 MREW 锁的对象。

增量将是当前(或稍微过时的)队列长度。此外,窗口/线程/对象将能够生成他自己的事件(例如,如果队列空闲、正常或溢出,则绘制一些仪表)

关于 MREW 锁,Delphi RTL 中有一个股票,OTL 库本身有另一个,还有人将 OmniMREW 移植到 Lzarus,然后制作了另一个他声称效率更高的锁。

于 2015-06-11T11:57:29.843 回答