Альтернативы внедрения зависимости от конструктора - PullRequest
0 голосов
/ 13 ноября 2018

Я работаю в одиночку над проектом учета рабочего времени сотрудника, который использует базу данных для хранения записей табеля рабочего времени. Я использую Delphi Pro 10.2.3 Tokyo для проекта и создал библиотеку классов-оболочек для облегчения работы с наборами данных, такими как обычные классы. Например, чтобы получить доступ к полю FirstName в таблице Employee, я могу написать LFirstName: = FEmployee.FirstName; вместо LFirstName: = Dataset.FieldByName ('FirstName'). AsString;

Некоторые из моих классов имеют значительное количество зависимостей (целых восемь), которые я внедряю через конструктор класса. Я использую объект домена для создания необходимых интерфейсов и вставки их в создаваемый класс. Некоторые интерфейсы, которые вводятся сами, также очень сложны, и становится все труднее отслеживать все в доменном объекте.

Внедряемые зависимости включают в себя интерфейсы-обертки для других таблиц, которые предоставляют значения поиска для вычисляемых полей, указатели на функции, которые создают объекты создания, используемые классом, или функции обратного вызова, которые разрешают отношения мастер / подробности. Эти отношения являются статическими и должны быть установлены в конструкторе, чтобы любые вычисляемые поля работали при создании класса.

Существуют ли альтернативы внедрению конструктора, которые могут снизить сложность конструктора при сохранении разделенных классов. Вот пример кода из одного из моих модулей для записей табеля рабочего времени.

unit LevelPay.DbModel.TimesheetEntry;

interface

uses
    Data.Db
  , FireDAC.Comp.DataSet
  , MyLib.Model.Interfaces
  , LevelPay.Model.Types
  , LevelPay.Model.Constants
  , LevelPay.Model.Interfaces
  , LevelPay.DbModel.AppModel
  ;

type
  TDbCustomTimesheetEntry = class(
    TDbAppModel<ITimesheetEntry>,
    ITimesheetEntry
    )
  strict private
    FCopyFunc: TCopyFunc<ITimesheetEntry>;
    procedure ClearFilter;
    procedure FilterEntries(const ADate: TDate);
  strict protected
    FTimesheet: ITimesheet;
    FID: TField;
    FEmployeeID: TField;
    FPayPeriodEndDate: TField;
    FFiscalYearEndDate: TField;
    FFiscalYearStartDate: TField;
    FRowNbr: TField;
    FEntryTypeID: TField;
    FDateIn: TField;
    FTimein: TField;
    FDateOut: TField;
    FTimeOut: TField;
    FCreatedBy: TField;
    FCreatedTimestamp: TField;
    FLastModifiedBy: TField;
    FLastModifiedTimestamp: TField;
    FNote: TField;
    FClockable: TField;
    FClockableHours: TField;
    FDayOfWeek: TField;
    FDifference: TField;
    FEmployeeName: TField;
    FEntryTypeCaption: TField;
    FTimeElapsed: TField;
    FDateIndex: TFDIndex;
    FTimeScheduled: TField;
    FScheduledTimeIn: TField;
    FScheduledTimeOut: TField;
    FWeekOf: TField;
    function GetID: TIdentifier;
    function GetModel: ITimesheetEntry; override;
    function GetClockable: Boolean;
    function GetClockableHours: THours;
    function GetDateIn: TDate;
    function GetDateOut: TDate;
    function GetDifference: THours;
    function GetEmployeeID: TIdentifier;
    function GetEmployeeName: string;
    function GetPayPeriodEndDate: TDate;
    function GetFiscalYearStartDate: TDate;
    function GetFiscalYearEndDate: TDate;
    function GetEntryTypeID: TIdentifier;
    function GetEntryTypeCaption: TCaption;
    function GetPlaceholder: Boolean;
    function GetRowNbr: TRowNbr;
    function GetScheduledTimeIn: TTime;
    function GetScheduledTimeOut: TTime;
    function GetTimeElapsed: THours;
    function GetTimein: TTime;
    function GetTimeOut: TTime;
    function GetTimeScheduled: THours;
    function GetWeekOf: TDate;
    function GetWeekDay: string;
    function GetCreatedBy: TUserName;
    function GetCreatedTimestamp: TDateTime;
    function GetLastModifiedBy: TUserName;
    function GetLastModifiedTimestamp: TDateTime;
    function GetNote: AnsiString;
    function GetEntry: ITimesheetEntry;
    function GetTimesheet: ITimesheet;
    function GetHasEntries: Boolean;
    function Find(AModel: ITimesheetEntry): Boolean; override;
    procedure DoUpdate(AModel: ITimesheetEntry); override;
    procedure Load; virtual;
    procedure CreateFields; override;
    procedure CreateCalcFields; override;
    procedure CreateIndexes; override;
    procedure FormatFields; override;
    procedure OnCalcFields(Dataset: TDataset); override;
    procedure OnNewRecord(Dataset: TDataset); override;
  public
    constructor Create(
      ADataset: TFDDataset;
      AModelFunc: TModelFunc<ITimesheetEntry>;
      ACopyFunc: TCopyFunc<ITimesheetEntry>;
      ATimesheet: ITimesheet;
      ACreateFields: Boolean
    ); reintroduce;
    property ID: TIdentifier read GetID;
    property EmployeeID: TIdentifier read GetEmployeeID;
    property PayPeriodEndDate: TDate read GetPayPeriodEndDate;
    property FiscalYearEndDate: TDate read GetFiscalYearEndDate;
    property FiscalYearStartDate: TDate read GetFiscalYearStartDate;
    property EntryTypeID: TIdentifier read GetEntryTypeID;
    property EntryTypeCaption: TCaption read GetEntryTypeCaption;
    property RowNbr: TRowNbr read GetRowNbr;
    property Clockable: Boolean read GetClockable;
    property ClockableHours: THours read GetClockableHours;
    property DateIn: TDate read GetDateIn;
    property EmployeeName: string read GetEmployeeName;
    property ScheduledTimeIn: TTime read GetScheduledTimeIn;
    property ScheduledTimeOut: TTime read GetScheduledTimeOut;
    property TimeIn: TTime read GetTimein;
    property DateOut: TDate read GetDateOut;
    property TimeOut: TTime read GetTimeOut;
    property TimeElapsed: THours read GetTimeElapsed;
    property Placeholder: Boolean read GetPlaceholder;
    property TimeScheduled: THours read GetTimeScheduled;
    property Difference: THours read GetDifference;
    property WeekDay: string read GetWeekDay;
    property WeekOf: TDate read GetWeekOf;
    property CreatedBy: TUserName read GetCreatedBy;
    property CreatedTimestamp: TDateTime read GetCreatedTimestamp;
    property LastModifiedBy: TUserName read GetLastModifiedBy;
    property LastModifiedTimestamp: TDateTime read GetLastModifiedTimestamp;
    property Note: AnsiString read GetNote;
    property Timesheet: ITimesheet read GetTimesheet;
  end;

  TDbSourceEntry = class(TDbCustomTimesheetEntry, ISourceEntryList)
  strict private
    FLoadTimesheetEntries: TLoadTimesheetProc;
    FElectionList: ILevelPayElectionList;
    FPositionList: IHourlyPositionList;
  strict protected
    procedure BeforePost(Dataset: TDataset); override;
    procedure Load; override;
  public
    constructor Create(
      ADataset: TFDDataset;
      AModelFunc: TModelFunc<ITimesheetEntry>;
      ATimesheet: ITimesheet;
      ACopyFunc: TCopyFunc<ITimesheetEntry>;
      AProc: TLoadTimesheetProc;
      AElectionList: ILevelPayElectionList;
      APositionList: IHourlyPositionList;
      ACreateFields: Boolean = True
    ); reintroduce;
  end;

  TDbDummyEntry = class(TDbCustomTimesheetEntry, IDummyEntryList)
  strict private
    FPlaceholderID: TIdentifier;
    FClosureList: ISchoolClosureList;
    procedure EntryTypeIDOnChange(Sender: TField);
  strict protected
    procedure AddPlacedholder(ADate: TDate; ARowNbr: TRowNbr);
    procedure CreateFields; override;
    procedure DoAdd(AModel: ITimesheetEntry); override;
    property PlaceholderID: TIdentifier read FPlaceholderID write FPlaceholderID;
  public
    constructor Create(
      ADataset: TFDDataset;
      AModelFunc: TModelFunc<ITimesheetEntry>;
      ACopyFunc: TCopyFunc<ITimesheetEntry>;
      ATimesheet: ITimesheet;
      AClosureList: ISchoolClosureList;
      ACreateFields: Boolean
    ); reintroduce;
  end;

  TDbTimesheetEntry = class(TDbDummyEntry, ITimesheetEntryList)
  strict private
    FClone: TFDDataset;
    FSource: ISourceEntryList;
    function GetNextRowNbr: TRowNbr;
  strict protected
    function WorkweekList: IWorkweekList;
    procedure Clear;
    procedure Load; override;
  public
    procedure Add(AModel: ITimesheetEntry); //replaces inherited add
    procedure Delete(AModel: ITimesheetEntry); //replace inherited delete
    procedure Update(OldModel, NewModel: ITimesheetEntry);
    constructor Create(
      ADataset: TFDDataset;
      AModelFunc: TModelFunc<ITimesheetEntry>;
      ACopyFunc: TCopyFunc<ITimesheetEntry>;
      ATimesheet: ITimesheet;
      ASourceFunc: TSourceListFunc;
      AClosureList: ISchoolClosureList;
      ACreateFields: Boolean
    ); reintroduce;
  end;

implementation

uses
    System.SysUtils
  , System.Classes
  , System.Variants
  , System.DateUtils
  , FireDAC.Comp.Client
  , DateTimeHelper
  , LevelPay.Model.Helpers
  ;

{ TCustomShift }

procedure TDbCustomTimesheetEntry.ClearFilter;
begin
  CancelRange;
end;

constructor TDbCustomTimesheetEntry.Create(ADataset: TFDDataset;
  AModelFunc: TModelFunc<ITimesheetEntry>; ACopyFunc: TCopyFunc<ITimesheetEntry>;
  ATimesheet: ITimesheet; ACreateFields: Boolean);
begin
  inherited Create(ADataset, AModelFunc, ACreateFields);
  FCopyFunc := ACopyFunc;
  FTimesheet := ATimesheet;
end;

procedure TDbCustomTimesheetEntry.CreateCalcFields;
begin
  inherited;
  FClockable           := CreateCalcBooleanField(k_Clockable);
  FClockableHours      := CreateCalcFloatField(k_ClockableHours);
  FDayOfWeek           := CreateCalcStringField(k_WeekDay, 13);
  FDifference          := CreateCalcFloatField(k_Difference);
  FEmployeeName        := CreateCalcStringField(k_EmployeeName, 40);
  FEntryTypeCaption    := CreateCalcStringField(k_EntryTypeCaption, 20);
  FFiscalYearEndDate   := CreateCalcDateTimeField(k_FiscalYearEndDate);
  FFiscalYearStartDate := CreateCalcDateTimeField(k_FiscalYearStartDate);
  FScheduledTimeIn     := CreateCalcDateTimeField(k_ScheduledTimeIn);
  FScheduledTimeOut    := CreateCalcDateTimeField(k_ScheduledTimeOut);
  FTimeElapsed         := CreateCalcFloatField(k_TimeElapsed);
  FTimeScheduled       := CreateCalcFloatField(k_TimeScheduled);
  FWeekOf              := CreateCalcDateTimeField(k_WeekOf);
end;

procedure TDbCustomTimesheetEntry.CreateFields;
begin
  FID                    := CreateField(k_Id);
  FEmployeeID            := CreateField(k_EmployeeID);
  FEntryTypeID           := CreateField(k_EntryTypeID);
  FRowNbr                := CreateField(k_RowNbr);
  FTimeIn                := CreateField(k_TimeIn);
  FTimeOut               := CreateField(k_TimeOut);
  FID                    := CreateField(k_ID);
  FDateIn                := CreateField(k_DateIn);
  FDateOut               := CreateField(k_DateOut);
  FCreatedBy             := CreateField(k_CreatedBy);
  FCreatedTimestamp      := CreateField(k_CreatedTimeStamp);
  FLastModifiedBy        := CreateField(k_LastModifiedBy);
  FLastModifiedTimestamp := CreateField(k_LastModifiedTimestamp);
  FNote                  := CreateField(k_Note);
  FPayPeriodEndDate      := CreateField(k_PayPeriodEndDate);

end;

procedure TDbCustomTimesheetEntry.CreateIndexes;
const
  FIELD_LIST = k_DateIn + ';' + k_RowNbr;
begin
  inherited;
  FDateIndex := CreateIndex('ByDate', FIELD_LIST);
  FDateIndex.Selected := True;
  Dataset.IndexesActive := True;
end;

function TDbCustomTimesheetEntry.GetClockable: Boolean;
begin
  Result := Rules.Clockable;
end;

function TDbCustomTimesheetEntry.GetClockableHours: THours;
begin
  Result := Rules.ClockableHours;
end;

function TDbCustomTimesheetEntry.GetCreatedBy: TUserName;
begin
  Result := FCreatedBy.AsUserName;
end;

function TDbCustomTimesheetEntry.GetCreatedTimestamp: TDateTime;
begin
  Result := FCreatedTimestamp.AsDateTime;
end;

function TDbCustomTimesheetEntry.GetDateIn: TDate;
begin
  Result := FDateIn.AsDateTime;
end;

function TDbCustomTimesheetEntry.GetDateOut: TDate;
begin
  Result := FDateOut.AsDateTime;
end;

function TDbCustomTimesheetEntry.GetDifference: THours;
begin
  Result := Rules.Difference;
end;

function TDbCustomTimesheetEntry.GetEmployeeID: TIdentifier;
begin
  Result := FEmployeeID.AsIdentifier;
end;

function TDbCustomTimesheetEntry.GetEmployeeName: string;
begin
  Result := Rules.EmployeeName;
end;

function TDbCustomTimesheetEntry.GetEntryTypeID: TIdentifier;
begin
  Result := FEntryTypeID.AsIdentifier;
end;

function TDbCustomTimesheetEntry.GetFiscalYearEndDate: TDate;
begin
  Result := FFiscalYearEndDate.AsDateTime;
end;

function TDbCustomTimesheetEntry.GetFiscalYearStartDate: TDate;
begin
  Result := FFiscalYearStartDate.AsDateTime;
end;

function TDbCustomTimesheetEntry.GetHasEntries: Boolean;
begin
  Result := RecordCount > 0;
end;

function TDbCustomTimesheetEntry.GetID: TIdentifier;
begin
  Result := FID.AsInteger;
end;

function TDbCustomTimesheetEntry.GetLastModifiedBy: TUserName;
begin
  Result := FLastModifiedBy.AsUserName;
end;

function TDbCustomTimesheetEntry.GetLastModifiedTimestamp: TDateTime;
begin
  Result := FLastModifiedTimestamp.AsDateTime;
end;

function TDbCustomTimesheetEntry.GetModel: ITimesheetEntry;
var
  LResult: ITimesheetEntry;
begin
  LResult := FCopyFunc(Self);
  Result := LResult;
end;

function TDbCustomTimesheetEntry.GetNote: AnsiString;
begin
  Result := FNote.AsAnsiString;
end;

function TDbCustomTimesheetEntry.GetPayPeriodEndDate: TDate;
begin
  Result := FPayPeriodEndDate.AsDateTime;
end;

function TDbCustomTimesheetEntry.GetPlaceholder: Boolean;
begin
  Result := Rules.Placeholder;
end;

function TDbCustomTimesheetEntry.GetEntry: ITimesheetEntry;
begin
  Result := Model;
end;

function TDbCustomTimesheetEntry.GetEntryTypeCaption: TCaption;
begin
  Result := Rules.EntryTypeCaption
end;

function TDbCustomTimesheetEntry.GetRowNbr: TRowNbr;
begin
  Result := FRowNbr.AsRowNbr;
end;

function TDbCustomTimesheetEntry.GetScheduledTimeIn: TTime;
begin
  Result := Rules.ScheduledTimeIn;
end;

function TDbCustomTimesheetEntry.GetScheduledTimeOut: TTime;
begin
  Result := Rules.ScheduledTimeOut;
end;

function TDbCustomTimesheetEntry.GetTimeElapsed: THours;
begin
  Result := Rules.TimeElapsed;
end;

function TDbCustomTimesheetEntry.GetTimein: TTime;
begin
  Result := FTimeIn.AsDateTime;
end;

function TDbCustomTimesheetEntry.GetTimeOut: TTime;
begin
  Result := FTimeOut.AsDateTime;
end;

function TDbCustomTimesheetEntry.GetTimeScheduled: THours;
begin
  Result := Rules.TimeScheduled;
end;

function TDbCustomTimesheetEntry.GetTimesheet: ITimesheet;
begin
  Result := FTimesheet;
end;

function TDbCustomTimesheetEntry.GetWeekDay: string;
begin
  Result := Rules.WeekDay;
end;

function TDbCustomTimesheetEntry.GetWeekOf: TDate;
begin
  Result := Rules.WeekOf;
end;

procedure TDbCustomTimesheetEntry.Load;
begin
  //Stub procedure
end;

procedure TDbCustomTimesheetEntry.OnCalcFields(Dataset: TDataset);
begin
  inherited;
  if not Assigned(Rules) then Exit;

  FClockable.AsBoolean         := GetClockable;
  FClockableHours.AsHours      := GetClockableHours;
  FDayOfWeek.AsString          := GetWeekDay;
  FDifference.AsHours          := GetDifference;
  FEmployeeName.AsString       := GetEmployeeName;
  FEntryTypeCaption.AsCaption  := GetEntryTypeCaption;
  FTimeElapsed.AsHours         := GetTimeElapsed;
  FTimeScheduled.AsHours       := GetTimeScheduled;
  FScheduledTimeIn.AsDateTime  := GetScheduledTimeIn;
  FScheduledTimeOut.AsDateTime := GetScheduledTimeOut;
  FWeekOf.AsDateTime           := GetWeekOf;
end;

procedure TDbCustomTimesheetEntry.OnNewRecord(Dataset: TDataset);
begin
  inherited;

  FEmployeeID.AsIdentifier        := FTimesheet.EmployeeID;
  FFiscalYearEndDate.AsDateTime   := FTimesheet.FiscalYearEndDate;
  FFiscalYearStartDate.AsDateTime := FTimesheet.FiscalYearStartDate;
  FPayPeriodEndDate.AsDateTime    := FTimesheet.PayPeriodEndDate;
end;

procedure TDbCustomTimesheetEntry.DoUpdate(AModel: ITimesheetEntry);
begin
  inherited;

  FEmployeeID.AsIdentifier  := AModel.EmployeeID;
  FRowNbr.AsRowNbr          := AModel.RowNbr;
  FEntryTypeID.AsIdentifier := AModel.EntryTypeID;
  FDateIn.AsDateTime        := AModel.DateIn;
  FTimeIn.AsDateTime        := AModel.TimeIn;
  FDateOut.AsDateTime       := AModel.DateOut;
  FTimeOut.AsDateTime       := AModel.TimeOut;
  FNote.AsAnsiString        := AModel.Note;
end;

procedure TDbCustomTimesheetEntry.FilterEntries(const ADate: TDate);
begin
  FDateIndex.Selected := True;
  SetRange([ADate], [ADate]);
end;

function TDbCustomTimesheetEntry.Find(AModel: ITimesheetEntry): Boolean;
begin
  Result := Locate(k_ID, AModel.ID);
end;

procedure TDbCustomTimesheetEntry.FormatFields;
begin
  inherited;
  FTimeElapsed.OnGetText    := HoursFieldGetText;
  FClockableHours.OnGetText := HoursFieldGetText;
  FDifference.OnGetText     := HoursFieldGetText;
  FTimeScheduled.OnGetText  := HoursFieldGetText;

  SetTimeFieldDisplayFormat(FTimeIn);
  SetTimeFieldDisplayFormat(FTimeOut);
  SetDateFieldDisplayFormat(FDateIn);
  SetDateFieldDisplayFormat(FDateOut);
  SetDateFieldDisplayFormat(FPayPeriodEndDate);
  SetSQLTimestampFieldDisplayFormat(FCreatedTimestamp);
  SetSQLTimestampFieldDisplayFormat(FLastModifiedTimestamp);
end;

{ TDbDummyEntry }

procedure TDbSourceEntry.BeforePost(Dataset: TDataset);
var
  LTimestamp: TDateTime;
begin
  inherited;
  LTimestamp := Now;
  FLastModifiedBy.AsUserName        := FTimesheet.User.UserName;
  FLastModifiedTimestamp.AsDateTime := LTimestamp;
  if State in [dsInsert] then
  begin
    FCreatedBy.AsUserName        := FTimesheet.User.UserName;
    FCreatedTimestamp.AsDateTime := LTimestamp;
  end;
end;

constructor TDbSourceEntry.Create(ADataset: TFDDataset;
  AModelFunc: TModelFunc<ITimesheetEntry>; ATimesheet: ITimesheet;
  ACopyFunc: TCopyFunc<ITimesheetEntry>; AProc: TLoadTimesheetProc;
  AElectionList: ILevelPayElectionList;   APositionList: IHourlyPositionList;
  ACreateFields: Boolean);
begin
  inherited Create(ADataset, AModelFunc, ACopyFunc, ATimesheet, ACreateFields);

  FLoadTimesheetEntries := AProc;
  FElectionList         := AElectionList;
  FPositionList         := APositionList;
end;

procedure TDbSourceEntry.Load;
var
  LEmployeeID: TIdentifier;
  LFirstEntryDate: TDate;
  LLastEntryDate: TDate;
begin
  LEmployeeID     := FTimesheet.EmployeeID;
  LFirstEntryDate := FTimesheet.FirstEntryDate;
  LLastEntryDate  := FTimesheet.LastEntryDate;
  FLoadTimesheetEntries(LEmployeeID, LFirstEntryDate, LLastEntryDate);
end;


{ TDbDummyEntry }

procedure TDbDummyEntry.AddPlacedholder(ADate: TDate; ARowNbr: TRowNbr);
var
  LEntryTypeID: TIdentifier;
  LClosure: ISchoolClosure;
  LNote: AnsiString;
  LRowNbr: TRowNbr;
begin
  Dec(FPlaceholderID);
  LNote        := '';
  LEntryTypeID := 0;
  LRowNbr      := ARowNbr;

  if LRowNbr < 2 then //This is a first entry for the date
  begin
  if FClosureList.Find(ADate) then
    begin
      LClosure := FClosureList.Closure;
      LEntryTypeID := LClosure.EntryTypeID;
      LNote := AnsiString(LClosure.Caption);
    end
    else
    begin
      if TDateTime(ADate).DayOfWeek in [MONDAY..FRIDAY] then
        LEntryTypeID := k_Regular
      else
        LEntryTypeID := 0;
    end;
  end;

  Append;
  FId.AsIdentifier          := FPlaceholderID;
  FRowNbr.AsRowNbr          := LRowNbr;
  FDateIn.AsDateTime        := ADate;
  FDateOut.AsDateTime       := ADate;
  FEntryTypeID.AsIdentifier := LEntryTypeID;
  FNote.AsAnsiString        := LNote;
  Post;
end;

constructor TDbDummyEntry.Create(ADataset: TFDDataset;
  AModelFunc: TModelFunc<ITimesheetEntry>; ACopyFunc: TCopyFunc<ITimesheetEntry>;
  ATimesheet: ITimesheet; AClosureList: ISchoolClosureList; ACreateFields: Boolean);
begin
  inherited Create(ADataset, AModelFunc, ACopyFunc, ATimesheet, ACreateFields);
  FClosureList  := AClosureList;
end;

procedure TDbDummyEntry.CreateFields;
begin
  inherited;
  FId.ReadOnly := False;
  FId.AutoGenerateValue := arNone;
  FEntryTypeID.OnChange := EntryTypeIDOnChange;
end;

procedure TDbDummyEntry.DoAdd(AModel: ITimesheetEntry);
begin
  inherited;
  FId.AsIdentifier := AModel.ID;
end;

procedure TDbDummyEntry.EntryTypeIDOnChange(Sender: TField);
var
  LDateIn: TDate;
  LDateOut: TDate;
begin
  if Sender.AsIdentifier = k_LandSchool then
  begin
    LDateIn  := FDateIn.AsDateTime;
    LDateOut := LDateIn + 1;
    FDateOut.AsDateTime := LDateOut;
    FTimeIn.AsDateTime  := GetScheduledTimeOut;
    FTimeOut.AsDateTime := GetScheduledTimeIn;
  end;
end;

{ TDbTimesheetEntry }

procedure TDbTimesheetEntry.Add(AModel: ITimesheetEntry);
var
  LEntry: ITimesheetEntry;
begin
  FSource.Add(AModel);
  LEntry := FSource.Entry; //Get model with updated ID
  FTimesheet.WorkweekList.AddEntry(LEntry);
  inherited Add(LEntry);
end;

procedure TDbTimesheetEntry.Clear;
begin
  PlaceholderID := 0;
  Dataset.CancelUpdates;
  DisableControls;
  try
    First;
    while RecordCount > 0 do
      Dataset.Delete;
  finally
    EnableControls;
  end;
end;

constructor TDbTimesheetEntry.Create(ADataset: TFDDataset;
  AModelFunc: TModelFunc<ITimesheetEntry>;
  ACopyFunc: TCopyFunc<ITimesheetEntry>; ATimesheet: ITimesheet;
  ASourceFunc: TSourceListFunc; AClosureList: ISchoolClosureList;
  ACreateFields: Boolean);
begin
  inherited Create(ADataset, AModelFunc, ACopyFunc, ATimesheet, AClosureList, ACreateFields);
  FSource := ASourceFunc(FTimesheet);

  FClone := TFDMemTable.Create(ADataset);
  FClone.CloneCursor(ADataset);
end;

procedure TDbTimesheetEntry.Delete(AModel: ITimesheetEntry);
var
  LDate: TDate;
  LRowNbr: SmallInt;
  LEntry: ITimesheetEntry;
begin
  FSource.Delete(AModel);
  WorkweekList.DeleteEntry(AModel);
  DisableControls;
  try
    LDate := AModel.DateIn;
    LRowNbr := AModel.RowNbr;
    inherited Delete(AModel);
    if (LRowNbr = 1) then
    begin
      AddPlacedholder(LDate, 0);
      LEntry := Model; //Get placeholder
      WorkweekList.AddEntry(LEntry);
    end;
  finally
    EnableControls;
  end;
end;

function TDbTimesheetEntry.GetNextRowNbr: TRowNbr;
begin
  Result := 0;
  FClone.SetRange([GetDateIn], [GetDateIn]);
  while not FClone.Eof do
  begin
    Result := FClone.FieldByName(k_RowNbr).AsRowNbr + 1;
    FClone.Next;
  end;
  FClone.CancelRange;
end;

procedure TDbTimesheetEntry.Load;
var
  LDate: TDate;
  LFirstEntryDate: TDate;
  LCutoffDate: TDate;
  LEntry: ITimesheetEntry;
  LWeekOf: TDate;
  LWorkweekList: IWorkweekList;
begin
  LWorkweekList   := FTimesheet.WorkweekList;
  LFirstEntryDate := FTimesheet.FirstEntryDate;
  LCutOffDate     := FTimesheet.LastEntryDate;
  LWeekOf         := TDateTime(LFirstEntryDate).StartOfWeek;

  LWorkweekList.Init(LFirstEntryDate, LCutOffDate);
  FSource.Load;
  DisableControls;
  try
    Clear;

    LDate := LWeekOf;
    repeat
      FSource.FilterEntries(LDate);
      if FSource.HasEntries then
      begin
        for LEntry in FSource do
        begin
          if LDate >= LFirstEntryDate then
          begin
            inherited Add(LEntry);  //this must call inherited add to adding to FSource
          end;
          LWorkweekList.AddEntry(LEntry);
        end;
      end
      else
      begin
        if LDate >= LFirstEntryDate then
        begin
          AddPlacedholder(LDate, 0);
          LEntry := GetModel; //This retrieves the placeholder
          LWorkweekList.AddEntry(LEntry);
        end;
      end;
      LDate := LDate + 1;
    until LDate > LCutOffDate;
  finally
    FSource.ClearFilter;
    EnableControls;
    First;
  end;
end;

procedure TDbTimesheetEntry.Update(OldModel, NewModel: ITimesheetEntry);
var
  LEntry: ITimesheetEntry;
begin
  DisableControls;
  try
    if Assigned(OldModel) then
    begin
      if OldModel.Placeholder then
      begin
        FSource.Add(NewModel);
      end
      else
      begin
        FSource.Update(NewModel);
      end;
      inherited Delete(OldModel);
      WorkweekList.DeleteEntry(OldModel);
    end
    else
    begin
      FSource.Add(NewModel);
    end;

    LEntry := FSource.Entry; //Get entry with new ID
    inherited Add(LEntry);
    WorkweekList.AddEntry(LEntry);
  finally
    EnableControls;
  end;
end;

function TDbTimesheetEntry.WorkweekList: IWorkweekList;
begin
  Result := FTimesheet.WorkweekList;
end;

end.

Ответы [ 2 ]

0 голосов
/ 13 ноября 2018

У вас есть свойство по умолчанию в корне все TDataSet:

property FieldValues[const FieldName: string]: Variant read GetFieldValue write SetFieldValue; default;

и вы можете использовать

aTest: TDataSet; //any descant
aValue := aTest['NameField'];

Зачем это усложнять инъекциями?
Синтаксис чистоты?
Как Paradox ObjectPAL с 1994 года.

0 голосов
/ 13 ноября 2018

Обычно говорят, что когда у вас много параметров конструктора (это означает зависимости), это признак того, что ваш класс может сделать слишком много (см. Принцип единственной ответственности).

Если определенные зависимости в большинстве случаев взаимодействуют только друг с другом, это признак того, что эти зависимости могут подвергаться их рефакторингу в свой собственный компонент / класс, который затем вводится. Это не только уменьшает зависимости в первую очередь, но и уменьшает сложность ваших компонентов.

Я предлагаю прочитать блог Марка Симанна, где он объяснил многие области, которые играют важную роль в правильной практике внедрения зависимостей, а также в разработке и архитектуре программного обеспечения.

Я помню только два примера:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...