Как мне провести рефакторинг этого базового класса и разделить его функциональность?
У меня есть базовый класс TBuilder
что наследует от TObjectList
, TBuilder
может выполнять операции, связанные с ADO, и заполнять его внутреннюю структуру результатами. В дополнение к этому, та же самая операция может быть сделана через Интернет, через вызовы HTTP. Возвращенные результаты также анализируются, а внутренняя структура обновляется.
С этого момента я генерирую файлы pas из таблицы базы данных, чтобы имитировать ее структуру. Скажем, у меня есть таблица с названием Company, я программно генерирую TCompany
объект, который также наследует от TBuilder
который затем может выбрать, каким он должен быть. На данный момент я строю TCompany
с типом, который говорит, что я хочу, чтобы он выполнял операции ADO или я хотел, чтобы он выполнял операции HTTP. 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;
Если я изменю тип, он запросит базу данных напрямую.
1 ответ
Опция 1)
Не наследуйте TCompany от TBuilder. Добавьте поле / свойство FBuilder: TBuilder в TCompany и задайте для него экземпляр TADOBuilder или TDSBuilder. А затем добавьте необходимые методы в TCompany, и эти методы должны будут вызвать требуемый метод в FBuilder. Конечно, необходимые методы должны быть объявлены как виртуальные в TBuilder, и TADOBuilder должен их переопределить.
Option2)
Отделите свой бизнес-объект (TCompany) от постоянного кода (TBuilder, TADOBuilder). Трудно дать конкретный совет, не зная деталей, но идея в том, что ваша TCompany должна быть независимой от постоянного кода. В общем случае вы добавляете все необходимые бизнес-свойства в TCompany (например, имя, адрес) и используете отдельный класс, который загружает данные в TCompany с помощью TBuilder или TADOBuilder и т. Д.
РЕДАКТИРОВАТЬ
Вот как это будет выглядеть с Option1.
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;
....
РЕДАКТИРОВАТЬ пример для варианта 2
TCompany = class
private
FId: Integer;
FName: string;
...
public
property Id: Integer read FId write FId;
property Name: string read FName write FName;
end;
TADOPerssiter = class
public
constructor Create(const aConnectionString: string);
// Creates and loads TCompany from ADO
function LoadCompany(aId: Integer): TCompany;
procedure SaveCompany(aCompany: TCompany);
end;
Добавить аналогичный класс для DS