我有一个基类TBuilder
,它继承自TObjectList
。 TBuilder
可以执行与ADO相关的操作,并使用结果填充其内部结构。除此之外,可以通过HTTP调用在Web上完成相同的操作。还解析返回的结果,并更新内部结构。
从这里开始,我从数据库表生成pas文件以模仿其结构。假设我有一个名为Company的表,我以编程方式生成了一个TCompany
对象,该对象也继承自TBuilder
,然后可以选择所需的对象。目前,我用一种说我希望它执行ADO操作或我要执行HTTP操作的类型构造TCompany
。 TBuilder
通常将具有一个加载过程,然后根据类型,它将生成SQL并从数据库(或http)加载并在内部用结果填充自身。
现在我现在要做的是将TBuilder
拆分成一个单元,从而知道如何通过ADO查询数据库,而另一个则知道如何通过HTTP查询数据库。我当时也在考虑从TBuilder
继承这两个类。但是我对TCompany
感到困惑,因为它需要继承自TBuilder
或TADOBuilder
或TDSBuilder
(后两个是新单位)。如果我继承自TADOBuilder
,则它只能代表一种对象。我正在努力使TCompany
可以随时成为两者之一。我看到您只能使用接口实现多重继承,但是我对此并不陌生,还无法弄清楚如何重新设计它,以使TCompany
可以同时是两种类型的对象。
有什么想法可以解决这个问题吗?暂时,我被困在Delphi 6中。
外观如下:
TCompany = class(TBuilder) //I generate this programatically. This represents a table in the database
private
fUser: TSecurityUser;
function GetCompanyName: TBuilderField;
function GetCompanyAbbreviation: TBuilderField;
function GetCompanyID: TBuilderField;
function GetDateCreated: TBuilderField;
function GetDeleted: TBuilderField;
public
Property CompanyID:TBuilderField read GetCompanyID;
Property CompanyName:TBuilderField read GetCompanyName;
Property Abbreviation:TBuilderField read GetCompanyAbbreviation;
property DateCreated:TBuilderField read GetDateCreated;
property Deleted:TBuilderField read GetDeleted;
property User:TSecurityUser read fUser Write fUser;
constructor NewObject(psCompanyName,psAbbreviation:string);
constructor Create(conType:TConnectionType = conTypeSQLServer);override;
当我试图以一种更智能的方式拆分成多个单独的单元时,这是加载过程的样子:
function TBuilder.Load(psSQL:string = ''; poLoadOptions:TLoadOptions = []; poConnectionType:TConnectionType = conNone): Boolean;
var
LoQuery:TADOQuery;
LoSQL:string;
LoConnectionType:TConnectionType;
begin
Result := True;
LoConnectionType := fConnectionType;
if poConnectionType <> conNone then
LoConnectionType := poConnectionType;
if LoConnectionType = conTypeSQLServer then
begin
LoQuery := TADOQuery.Create(nil);
Try
try
LoQuery.Connection := uBuilder.ADOConnection;
LoSQL := psSQL;
if LoSQL = '' then
LoSQL := BuildSelectSQL;
LoQuery.SQL.Text := LoSQL;
LoQuery.Open;
LoadFromDataset(LoQuery);
except on E:exception do
begin
Error := E.Message;
Result := False;
end;
end;
Finally
FreeAndNil(LoQuery);
end;
end else
if fConnectionType = conTypeDatasnap then
begin
fWebCallType := sqlSelect;
try
if Assigned(fParent) then
if fParent.Error <> '' then
Exit;
if Assigned(OnBusyLoadingHook) then
OnBusyLoadingHook('Busy loading...');
{Reset the msg}
if Assigned(OnDisplayVisualError) then
OnDisplayVisualError(imtRed,'');
if (poLoadOptions <> LoadOptions) then
LoadOptions := LoadOptions + poLoadOptions;
Result := InternalLoad(loFullyRecursiveLoad in LoadOptions);
finally
{ We're done loading }
if Assigned(OnBusyLoadingHook) then
OnBusyLoadingHook('');
end;
end;
end;
然后我将以这种方式使用该对象:
var
LoCompany:TCompany;
begin
LoCompany := TCompany.Create(conTypeDatasnap);
LoCompany.CompanyName.Value := 'Test';
LoCompany.Load; //This will then generate the appropriate JSON and pass it via idhttp component to the server and the results will be parsed into its structure.
end;
如果更改类型,它将直接查询数据库。
答案 0 :(得分:2)
选项1)
不要从TBuilder继承TCompany。向TCompany添加一个FBuilder:TBuilder字段/属性,并将其设置为TADOBuilder或TDSBuilder实例。然后将所需的方法添加到TCompany,这些方法将需要在FBuilder上调用所需的方法。当然,必须在TBuilder上将所需的方法声明为虚拟方法,而TADOBuilder则需要重写这些方法。
选项2)
将业务对象(TCompany)与持久性代码(TBuilder,TADOBuilder)分开。在不知道细节的情况下很难给出具体的建议,但其想法是您的TCompany应该独立于持久性代码。通常,您将所有必需的业务属性添加到TCompany(例如,名称,地址),并使用单独的类,该类使用TBuilder或TADOBuilder等将数据加载到TCompany中。
编辑
这是Option1的外观。
ngork
选项2的编辑示例
TBuilder = abstract class
procedure Load; virtual;
end;
TADOBuilder = class(TBuilder)
procedure Load; override;
end;
TDSBuilder = class(TBuilder)
procedure Load; override;
end;
TCompany = class
private
FBuilder: TBuilder;
public
constructor Create(aBuilder: TBuilder);
procedure Load;
end;
{ TCompany }
constructor TCompany.Create(aBuilder: TBuilder);
begin
inherited;
FBuilder := aBuilder;
end;
procedure TCompany.Load;
begin
FBuilder.Load;
end;
....
为DS添加类似的类