http://www.lazyproject.info/
Прикольненько конечно.
Я правда последнее время старался двигаться в сторону "обратную RAD".
Прикольненько конечно.
Я правда последнее время старался двигаться в сторону "обратную RAD".
Блог человека, который 18-ть лет программирует на Delphi. И 25 лет программирует вообще. VCL, UML, MDA, тесты. Это не "учебник", это - "заметки на полях".
List.Add(TItem.Create);
Item := TItem.Create; // колическтво ссылок рано 1 try List.Add(Item); // количество ссылок равно 2 finally FreeAndNil(Item); // количество ссылок равно 1 end;
List.Add(TItem.Create.Autorelease);
A := TMyClass.Create;
A := TMyClass.NewInstance; A.Create;
A.Destroy;
A.Destroy; A.DestroyInstance
{$IfNDef RefCountedPrim_imp} {$Define RefCountedPrim_imp} _RefCountedPrim_ = {mixin} class(_RefCountedPrim_Parent_) private // private fields f_RefCount : Integer; {* Поле для свойства RefCount} protected // overridden protected methods procedure FreeInstance; override; public // overridden public methods destructor Destroy; override; class function NewInstance: TObject; override; protected // protected methods procedure Cleanup; virtual; {* Функция очистки полей объекта. } public // public methods function Use: Pointer; {* увеличить счетчик ссылок на 1 и вернуть указатель на себя. } function SetRefTo(var F): Boolean; public // public properties property RefCount: Integer read f_RefCount; end;//_RefCountedPrim_ {$Else RefCountedPrim_imp} // start class _RefCountedPrim_ procedure _RefCountedPrim_.Cleanup; begin end;//_RefCountedPrim_.Cleanup function _RefCountedPrim_.Use: Pointer; begin if (Self <> nil) then InterlockedIncrement(f_RefCount); Result := Self; end;//_RefCountedPrim_.Use function _RefCountedPrim_.SetRefTo(var F): Boolean; begin if (Pointer(F) = Self) then Result := false else begin Result := true; TObject(F).Free; Pointer(F) := Self.Use; end;//Pointer(F) = V end;//_RefCountedPrim_.SetRefTo destructor _RefCountedPrim_.Destroy; begin if (InterlockedDecrement(f_RefCount) = 0) then begin Inc(f_RefCount); try try Cleanup; finally inherited Destroy; end;//try..finally finally Dec(f_RefCount); end;{try..finally} end;//InterlockedDecrement(f_RefCount) = 0 end;//_RefCountedPrim_.Destroy class function _RefCountedPrim_.NewInstance: TObject; begin Result := inherited NewInstance; _RefCounted_(Result).Use; end;//_RefCountedPrim_.NewInstance procedure _RefCountedPrim_.FreeInstance; begin if (f_RefCount = 0) then inherited FreeInstance; end;//_RefCountedPrim_.FreeInstance {$EndIf RefCountedPrim_imp}
{$IfNDef RefCounted_imp} {$Define RefCounted_imp} _RefCountedPrim_Parent_ = _RefCounted_Parent_; {$Include RefCountedPrim.imp.pas} _RefCounted_ = {mixin} class(_RefCountedPrim_) protected // protected methods destructor Destroy; {* Это чтобы не было соблазна перекрывать destroy. } end;//_RefCounted_ {$Else RefCounted_imp} type _RefCountedPrim_R_ = _RefCounted_; {$Include RefCountedPrim.imp.pas} // start class _RefCounted_ destructor _RefCounted_.Destroy; begin assert(false, 'По идее мы попасть сюда не должны'); inherited; end;//_RefCounted_.Destroy {$EndIf RefCounted_imp}
unit Refcounted; interface type _RefCounted_Parent_ = TObject; {$Include RefCounted.imp.pas} TRefcounted = class(_RefCounted_) end;//TRefcounted implementation uses Windows ; {$Include RefCounted.imp.pas} end.
unit RefcountedTest; interface uses BaseTest ; type TRefcountedTest = class(TBaseTest) published // published methods procedure DoIt; end;//TRefcountedTest implementation uses Refcounted, SysUtils, TestFrameWork ; // start class TRefcountedTest procedure TRefcountedTest.DoIt; var l_A : TRefcounted; l_B : TRefcounted; begin l_A := TRefcounted.Create; try Check(l_A.RefCount = 1); l_B := l_A.Use; try Check(l_A.RefCount = 2); Check(l_B.RefCount = 2); finally FreeAndNil(l_B); end;//try..finally Check(l_A.RefCount = 1); finally FreeAndNil(l_A); end;//try..finally end;//TRefcountedTest.DoIt initialization TestFramework.RegisterTest(TRefcountedTest.Suite); end.
Мне кажется, первая часть получилась намного интересней. Она была намного проще и не требовала много времени, фокусировалась на основном наборе навыков. Вторая часть более серьезная, особенно трудно было “заставить” участников писать код по-другому, не так как они привыкли. Вот одна из цитат из переписки:
Это у меня привычка такая, думать наперёд… тесты я выполнял последовательно.. и в конце уже начал понимать, что действительно, в тестах есть такой плюс. Ведь думая, а как оно будет в будущем: а) отвлекаешься б) чем больше объём, тем тяжелее это удержать в голове. Тесты рулят.
{$IfNDef RegionableControl_imp} {$Define RegionableControl_imp} _RegionableControl_ = {mixin} class(_RegionableControl_Parent_) {* Контрол с поддержкой регионов } private // private fields f_Reg : Tl3Region; private // private methods procedure UpdateRegion; procedure ClearRegion; procedure CMVisibleChanged(var Message: TMessage); message CM_VISIBLECHANGED; protected // overridden protected methods procedure Cleanup; override; {* Функция очистки полей объекта. } procedure CreateWnd; override; procedure DestroyWnd; override; procedure Resize; override; procedure VisibleChanging; override; protected // protected methods procedure TuneRegion(aRegion: Tl3Region); virtual; end;//_RegionableControl_ {$Else RegionableControl_imp} // start class _RegionableControl_ procedure _RegionableControl_.UpdateRegion; begin ClearRegion; if (f_Reg = nil) then f_Reg := Tl3Region.Create else f_Reg.FreeRgn; if (Width > 0) AND (Height > 0) AND Visible then begin if HandleAllocated then begin TuneRegion(f_Reg); if not f_Reg.Empty then SetWindowRgn(Handle, f_Reg.Rgn, true); end;//HandleAllocated end;//Visible end;//_RegionableControl_.UpdateRegion procedure _RegionableControl_.ClearRegion; begin if HandleAllocated then SetWindowRgn(Handle, 0, false); end;//_RegionableControl_.ClearRegion procedure _RegionableControl_.TuneRegion(aRegion: Tl3Region); begin // - ничего не делаем, полагаемся на потомков end;//_RegionableControl_.TuneRegion procedure _RegionableControl_.CMVisibleChanged(var Message: TMessage); begin inherited; UpdateRegion; end;//_RegionableControl_.CMVisibleChanged procedure _RegionableControl_.Cleanup; begin ClearRegion; FreeAndNil(f_Reg); inherited; end;//_RegionableControl_.Cleanup procedure _RegionableControl_.CreateWnd; begin inherited; UpdateRegion; end;//_RegionableControl_.CreateWnd procedure _RegionableControl_.DestroyWnd; begin ClearRegion; inherited; end;//_RegionableControl_.DestroyWnd procedure _RegionableControl_.Resize; begin inherited; UpdateRegion; end;//_RegionableControl_.Resize procedure _RegionableControl_.VisibleChanging; begin inherited; //UpdateRegion; end;//_RegionableControl_.VisibleChanging {$EndIf RegionableControl_imp}
{$IfNDef RoundedControl_imp} {$Define RoundedControl_imp} _RegionableControl_Parent_ = _RoundedControl_Parent_; {$Include RegionableControl.imp.pas} _RoundedControl_ = {mixin} class(_RegionableControl_) protected // overridden protected methods procedure TuneRegion(aRegion: Tl3Region); override; end;//_RoundedControl_ {$Else RoundedControl_imp} {$Include RegionableControl.imp.pas} // start class _RoundedControl_ procedure _RoundedControl_.TuneRegion(aRegion: Tl3Region); const cRad = 15; var l_R : Tl3Region; begin l_R := Tl3Region.Create; try l_R.Rgn := CreateRoundRectRgn(1, 0, Width + 1, Height, cRad, cRad); aRegion.Combine(l_R, RGN_OR); //aRegion.CombineRect(l3SRect(Width - cRad, 0, Width, Height), RGN_OR); finally FreeAndNil(l_R); end;//try..fianlly end;//_RoundedControl_.TuneRegion {$EndIf RoundedControl_imp}
unit RoundedButton; interface uses StdCtrls, Messages, l3Region, Controls {a} ; type _RefCounted_Parent_ = TButton; {$Include RefCounted.imp.pas} _RoundedControl_Parent_ = _RefCounted_; {$Include RoundedControl.imp.pas} TRoundedButton = class(_RoundedControl_) end;//TRoundedButton implementation uses Windows, SysUtils, Themes ; {$Include RefCounted.imp.pas} {$Include RoundedControl.imp.pas} end.
unit RoundedEdit; interface uses StdCtrls, Messages, l3Region, Controls {a} ; type _RefCounted_Parent_ = TEdit; {$Include RefCounted.imp.pas} _RoundedControl_Parent_ = _RefCounted_; {$Include RoundedControl.imp.pas} TRoundedEdit = class(_RoundedControl_) end;//TRoundedEdit implementation uses Windows, SysUtils, Themes ; {$Include RefCounted.imp.pas} {$Include RoundedControl.imp.pas} end.
unit RoundedControlsTest; interface uses TestFrameWork ; type TRoundedControlsTest = class(TTestCase) published // published methods procedure DoIt; end;//TRoundedControlsTest implementation uses RoundedButton, RoundedEdit, Forms ; // start class TRoundedControlsTest procedure TRoundedControlsTest.DoIt; var l_Form : TCustomForm; l_E : TRoundedEdit; l_B : TRoundedButton; begin l_Form := TCustomForm.CreateNew(Application); l_E := TRoundedEdit.Create(l_Form); l_B := TRoundedButton.Create(l_Form); l_Form.Height := 200; l_Form.Width := 200; l_E.Left := 10; l_B.Left := 10; l_E.Top := 20; l_B.Top := 50; l_E.Parent := l_Form; l_B.Parent := l_Form; l_Form.Show; end;//TRoundedControlsTest.DoIt initialization TestFramework.RegisterTest(TRoundedControlsTest.Suite); end.
procedure TIntStackTest.DoIt; const cEtalons : array [0..3] of integer = (10, 20, 3, 5); var l_S : TIntStack; l_I : Integer; begin l_S := TIntStack.Create; try for l_I := Low(cEtalons) to High(cEtalons) do l_S.Push(cEtalons[l_I]); for l_I := High(cEtalons) downto Low(cEtalons) do Check(l_S.Pop = cEtalons[l_I]); finally FreeAndNil(l_S); end;//try..finally end;//TIntStackTest.DoIt
procedure TStringStackTest.DoIt; const cEtalons : array [0..3] of String = ('мыма', 'мыла', 'раму', 'весело'); var l_S : TStringStack; l_I : Integer; begin l_S := TStringStack.Create; try for l_I := Low(cEtalons) to High(cEtalons) do l_S.Push(cEtalons[l_I]); for l_I := High(cEtalons) downto Low(cEtalons) do Check(l_S.Pop = cEtalons[l_I]); finally FreeAndNil(l_S); end;//try..finally end;//TStringStackTest.DoIt
SandBox.dpr: program SandBoxTest; uses TestFrameWork GUITestRunner, IntStack, IntStackTest, StringStack, StringStackTest, IntStackTestViaMixIn, StringStackTestViaMixIn ; begin GUITestRunner.RunRegisteredTests; end.
{$IfNDef StackTest_imp} {$Define StackTest_imp} TEtalonData = ItemsHolder; _StackTest_ = {mixin} class(TTestCase) published procedure DoIt; protected // protected methods function GetEtalonData: TEtalonData; virtual; abstract; function ArrayToEtalon(const aData: array of _ItemType_): TEtalonData; {* Вспомогательная функция появившаяся оттого, что динамические массивы умеет к открытым приводиться автоматом, а обратно - нет } end;//_StackTest_ {$Else StackTest_imp} procedure _StackTest_.DoIt; var l_Etalons : TEtalonData; l_S : _StackType_; l_I : Integer; begin l_S := _StackType_.Create; try l_Etalons := GetEtalonData; for l_I := Low(l_Etalons) to High(l_Etalons) do l_S.Push(l_Etalons[l_I]); for l_I := High(l_Etalons) downto Low(l_Etalons) do Check(l_S.Pop = l_Etalons[l_I]); finally FreeAndNil(l_S); end;//try..finally end; function _StackTest_.ArrayToEtalon(const aData: array of _ItemType_): TEtalonData; var l_I : Integer; begin SetLength(Result, Length(aData)); for l_I := Low(aData) to High(aData) do Result[l_I] := aData[l_I]; end; {$EndIf StackTest_imp}
unit IntStackTestViaMixIn; interface uses IntStack, TestFrameWork ; type _StackType_ = TIntStack; {$Include StackTest.imp.pas} TIntStackTestViaMixIn = class(_StackTest_) protected // realized methods function GetEtalonData: TEtalonData; override; end;//TIntStackTestViaMixIn implementation uses SysUtils ; {$Include StackTest.imp.pas} function TIntStackTestViaMixIn.GetEtalonData: TEtalonData; begin Result := ArrayToEtalon([10, 20, 3, 5, 6, 19, 21]); end; initialization TestFramework.RegisterTest(TIntStackTestViaMixIn.Suite); end.
unit StringStackTestViaMixIn; interface uses StringStack, TestFrameWork ; type _StackType_ = TStringStack; {$Include StackTest.imp.pas} TStringStackTestViaMixIn = class(_StackTest_) protected // realized methods function GetEtalonData: TEtalonData; override; end;//TStringStackTestViaMixIn implementation uses SysUtils ; {$Include StackTest.imp.pas} function TStringStackTestViaMixIn.GetEtalonData: TEtalonData; begin Result := ArrayToEtalon(['мама', 'мыла', 'раму', 'весело', 'и', 'споро']); end; initialization TestFramework.RegisterTest(TStringStackTestViaMixIn.Suite); end.