-1

我有一个父类,它可以有 2 个可能的子类:

  TEmailBaseAccount = class
    Connected: boolean;

    setting: TEmailAccountSettings;
    folders: TEmailAccountFolders;
    procedure Connect; virtual; abstract;
  end;

  TEmailIMAPAccount = class(TEmailBaseAccount)
    IdIMAP4: TIdIMAP4;
    OpenSSLHandler: TIdSSLIOHandlerSocketOpenSSL;

    procedure Connect; override;
  end;

  TlEmailPOP3Account = class(TEmailBaseAccount)
    IdPOP3: TIdIPOP3;
    OpenSSLHandler: TIdSSLIOHandlerSocketOpenSSL;

    procedure Connect; override;
  end;

我正在使用通用 TList 维护电子邮件帐户列表:

  TEmailAccountList = class(TList<TEmailBaseAccount>)
    procedure SaveToStream(Stream: TStream);
    procedure LoadFromStream(Stream: TStream);
    constructor Create(AOwner: TObject);
    destructor Destroy;
  end;

并使用以下代码将电子邮件帐户添加到列表中:

procedure TEmailAccountList.LoadFromStream(Stream: TStream);
var
  a, c: Integer;
  e: TEmailBaseAccount;
begin
  c := ReadStreamInt(Stream);
  for a := 0 to c - 1 do
  begin
    e := TEmailBaseAccount.Create(FOwnerEmailEngine);  
    e.LoadFromStream(Stream);
    Add(e);
  end;

end;

procedure TEmailAccountList.SaveToStream(Stream: TStream);
var
  a, c: Integer;
  e: TEmailBaseAccount;
begin
  c := Count;
  WriteStreamInt(Stream, c);
  for a := 0 to Count - 1 do
    Items[a].SaveToStream(Stream);
end;

在运行时,我需要使用以下方式区分两种类型的子类:

 if account is TEmailIMAPAccount then
  ...
 else if account is TEmailPOP3Account then
  ...

我确信我原来的类声明和 TList 声明不适合这个要求。在这种情况下需要进行哪些更改?

TIA。

4

2 回答 2

1

您的类型声明绝对没问题。您的问题大概是当您从流中读取一个项目时,您不知道它是什么类型。您不能使用 is 因为您还没有实例。

通过将类型代码写入每个实例的流来解决该问题。从流中读取时,读取类型代码并使用它来确定要实例化的类型。

使用发出 XML、JSON、YAML 等的持久性框架,这种持久性流式传输要容易得多。

于 2013-05-12T16:00:54.680 回答
0

我不会序列化完整的、高度特定于实现的对象,而只会将帐户属性(邮件帐户类型、用户凭据、服务器/端口/安全设置)写入文件。

这允许在不破坏现有设置文件兼容性的情况下修改实现。

我什至不会考虑if <object> is <class> ... else if <object> is <otherclass> ...解决方案。相反,定义一个简单的枚举类型TAccountType = (atPOP3, atIMAP),然后根据 Account 的 account type 属性在 case 结构中分支,或者使用Strategy 模式

于 2013-05-12T16:56:36.693 回答