我有一个父类,可以有两个可能的子类:
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。
答案 0 :(得分:1)
你的类型声明绝对没问题。你的问题可能是当你从流中读取一个项目时,你不知道它是什么类型。你不能使用is,因为你还没有实例。
通过为每个实例的流写入类型代码来解决该问题。从流中读取时,请读取类型代码并使用它来确定要实例化的类型。
使用发布XML,JSON,YAML等的持久性框架,这种持久性流式传输非常容易。
答案 1 :(得分:0)
我只会将帐户属性(邮件帐户类型,用户凭据,服务器/端口/安全设置)写入文件,而不是序列化完整的,特定于高度实现的对象。
这允许在不破坏现有设置文件兼容性的情况下修改实现。
我甚至不会考虑if <object> is <class> ... else if <object> is <otherclass> ...
解决方案。相反,定义一个简单的枚举类型TAccountType = (atPOP3, atIMAP)
,然后根据帐户的帐户类型属性在案例结构中进行分支,或使用Strategy pattern。