Biri bizi gözetliyor !

iki hafta once pespese yasanan elektrik arizalarindan dolayi modem sizlere omur oldu. garantiye gitti geldi bizde bu firsattan yararlanarak bol bol uyuduk, filmler izledik :) ve yeniden onlinem artik…

bu sure icerisinde net ve delphi alemine kisitli bir zaman ayirmak zorunda kaldim. tabi bir de malum ramazandayiz. iftar, sahur, davetler falan derken zaman su gibi akip gecti. su demisken bu ramazanda nedense fazla susuyorum(!) ben…

nete ayirabildigim bu kisitli zaman icerisinde forumda yer alan bilesenlerdeki degisiklikleri takip etmek gibi bir konuya gozup carpti. tasarim kaliplarinda bu gibi durumlar icin kullanilabilecek bazi ornekler mevcut. mesela Observer.

observer.JPG

bu gibi bir durumda aklimiza gelen ilk cozum soyle olacaktir.
degisiklikleri takip edecegim TEdit, TCheckBox gibi bilesenlerin OnChange olaylarinda Global bir Boolean degiskenin degerini set etmek. Ardından form kapanırken bu degiskenin degerini kontrol edip kullanicinin bu bilesenlerde her hangi bir degisiklik yapip yapmadigini kontrol etmek. ilk basta cazip bir cozum yolu gibi gorunsede bilesen sayisi arttikca ve bazi bilesenlerin onChange olaylarina degisik kodlar yazmak istedigimiz zaman basimizi agritabilecek bir durum. ustelik bu cozum hicte nesnesel bir cozum olmadigindan birim testi yazmak gibi bir durum da soz konusu olmayacak. kisacasi pratik bir cozum gibi gorunsede hicte saglam ve mantikli bir cozum degil. bunun yerine daha nesneye dayali bir cozum gelistrimemeiz lazim. simdi bu cozumu inceleyelim.

Temel fikrimiz su. olusturacagimiz bir nesneye degisikliklerini izlemek istedigimiz bilesenleri kayit etmek ve deigisiklikleri izleme isini bu nesneye yikip isin icinden siyrilmak :) ilk basta biraz fazla kod yazmak gerekiyor ama ardindan yeni bir bileseni izlemek icin tek yapmaniz gereken Izleyici.IzlenecekBilesenEkle(Edit1) gibi bir satir yazmak. Hepsi bu !

Simdi biraz daha derinlere inmenin vaktidir :)
Bir nesne bir bilesenin sahip oldugu degerin degisip degismedigini nasil anlayabilir ?
Ogreterek :)

Izleyici sınıfına takip etmek istedigimiz bilesenlerin degerlerinin degisip degismedigini ogretmekle ise baslamamiz gerekiyor. Bu nedenle Izlenecek her bilesen icin bir sınıf tanimlamamiz lazim. Bu sınıf ilgili nesnenin ilk degeri saklamali ve ona bir degisiklik var mi? diye sordugumuzda bize cevap verebilmeli. Her sınıf ayni adli metodlara sahip olacagindan bi tane soyut (abstract) ata sinif tanimlamam isimi baya kolaylastiracak.

burdaki abstract factory kalibinina gozatmaniz da fayda olabilir.

işte soyut sinifimiz..

TAbstractIzlenenBilesen = Class
Private
fEskiDeger:String;
fIzlenenBilesen:TControl;
Procedure IzlenenBileseninIlkDegeriniKaydet;virtual;abstract;
Public
constructor Create(IzlenecekBilesen:TControl);
Function GetIzlenenBilesenName:String;
Function IzlenenBilesendeDegisiklikVarMi():Boolean;virtual;abstract;
end;

fEskiDeger: Bilesenin ilk degerini sakladigimiz degisken

fIzlenenBilesen : Form uzerinde takip ettigimiz bilesen. Edit1, CheckBox1 gibi.

Procedure IzlenenBileseninIlkDegeriniKaydet;virtual;abstract; : Bilesenin ilk degerini kaydeden soyut metodumuz. Soyut cunku bilesenin sakladigi degerin ne oldugunu simdilik bilimyoruz. String bir deger de olabilir, boolean bir deger de olabilir integer bir degerde. daha sonraki siniflar bu metodu ezerek uygun sekilde yeniden tanimlamak zorundalar.

constructor Create(IzlenecekBilesen:TControl); : ilk ayarlari yaptigimiz yapilandirici.

constructor TAbstractIzlenenBilesen.Create(IzlenecekBilesen:TControl);
begin
fIzlenenBilesen :=IzlenecekBilesen;
IzlenenBileseninIlkDegeriniKaydet;
end;

Function GetIzlenenBilesenName:String; : İzlenen bilesenin adini ogrenmek icin kullaniyoruz. listeden silmek icin gerekli.

Function IzlenenBilesendeDegisiklikVarMi():Boolean;virtual;abstract; İlkDegeriniKaydet adli metod icin soylediklerimiz bunun icinde gecerli.

Simdi TEdit tipinde bir bileseni izleyebilmek icin gerekli sinifi tanimlayalim.

TIzlenenTEdit=Class(TAbstractIzlenenBilesen)
Private
Procedure IzlenenBileseninIlkDegeriniKaydet;Override;
Public
Function IzlenenBilesendeDegisiklikVarMi():Boolean;override;
end;

ata sinifta tanimladigimiz soyut metodlari eziyor ve TEdite uygun sekilde yaziyoruz.

procedure TIzlenenTEdit.IzlenenBileseninIlkDegeriniKaydet;
begin
inherited;
fEskiDeger:= (fIzlenenBilesen as TEdit).Text;
end;

function TIzlenenTEdit.IzlenenBilesendeDegisiklikVarMi: Boolean;
begin
Result:= Not ((fIzlenenBilesen as TEdit).Text = fEskiDeger);
end;

TEdit’in degismesi demek Text ozelliginin degismesi demek oldugundan Text alanini sakliyor ve ardindan bu alani ilk degerle karsilastirip degisiklik var mi yok mu ogreniyorum.

birde TCheckBox icin gorelim.

TIzlenenTCheckBox=Class(TAbstractIzlenenBilesen)
Private
Procedure IzlenenBileseninIlkDegeriniKaydet;Override;
Public
Function IzlenenBilesendeDegisiklikVarMi():Boolean;override;
end;



procedure TIzlenenTCheckBox.IzlenenBileseninIlkDegeriniKaydet;
begin
inherited;
fEskiDeger:= BoolToStr((fIzlenenBilesen as TCheckBox).Checked);
end;

function TIzlenenTCheckBox.IzlenenBilesendeDegisiklikVarMi: Boolean;
begin
Result:= Not (booltostr((fIzlenenBilesen as TCheckBox).Checked) = fEskiDeger);
end;

Burda da CheckBox in Checked ozelligini kontrol ediyorum.

bu da combobox icin.

TIzlenenComboBox=Class(TAbstractIzlenenBilesen)
Private
fEskiItemIndex:Integer;
Procedure IzlenenBileseninIlkDegeriniKaydet;Override;
Public
Function IzlenenBilesendeDegisiklikVarMi():Boolean;override;
end;

Comboboxa yeni bir alan ekliyorum. Bu alanda Itemindexi sakliyorum. texti degismeiz olabilir ama itemindexi degismistir belki :)

procedure TIzlenenComboBox.IzlenenBileseninIlkDegeriniKaydet;
begin
inherited;
fEskiDeger := (fIzlenenBilesen as TComboBox).Text;
fEskiItemIndex := (fIzlenenBilesen as TComboBox).ItemIndex;
end;

function TIzlenenComboBox.IzlenenBilesendeDegisiklikVarMi: Boolean;
begin
Result:= Not ((fIzlenenBilesen as TComboBox).Text = fEskiDeger);
Result:= (Result) or (Not ((fIzlenenBilesen as TComboBox).ItemIndex = fEskiItemIndex));
end;

siniflarimiz simdilik bunlar. yeni siniflar eklemek ihtiyaclariniza kalmis…….

simdi bu siniflari kullanarak ilgili bilesenleri izleycek olan izleyici sinifinin tanimina bakalim.

TIzleyici = class
private
fListIzlenenBilesenler:TObjectList;
fObje:TAbstractIzlenenBilesen;
{ Private declarations }
public
Function BilesenlerdeDegisiklikVarMi():Boolean;
Procedure IzlenecekBilesenEkle(IzlenecekBilesen:TControl);
Procedure IzlenecekBilesenSil(SilinecekBilesen:TControl);
constructor Create;
destructor Destroy;Override;
property IzlenenBilesenler:TObjectList read fListIzlenenBilesenler;
{ Public declarations }
end;

fListIzlenenBilesenler:TObjectList; : izlenen bilesenleri sakladigimiz liste.
fObje:TAbstractIzlenenBilesen; : yeni bilesenler eklemek icin kullanmamiz gereken nesne.

metodlar gayet acik sanirim. aciklama yapmaya gerek yok :)

//liste olusturuluyor…
//TObjectList.Create(True); True oldugu zaman kendi yok oldugu zaman sahip oldugu nesneleri
// de kendisi otomatik olarak yokedebilecek kadar akillii :) constructor TIzleyici.Create;
begin
inherited Create;
fListIzlenenBilesenler :=TObjectList.Create(True);
end;

//liste yokediliyor…
destructor TIzleyici.Destroy;
begin
fListIzlenenBilesenler.Free;
fListIzlenenBilesenler :=Nil;
inherited Destroy;
end;

//Simdilik 4 sinif destekliyor. Tedit, TCheckbox, TComboBox ve TSpinEdit
//gelen bilesenin Classname’i kontrol edilip uygun sinif create ediliyor ve olusturulan
//sinif listeye ekleniyor…

procedure TIzleyici.IzlenecekBilesenEkle(IzlenecekBilesen: TControl);
begin

fObje :=nil;
if IzlenecekBilesen.ClassName = ‘TEdit’ Then
fObje :=TIzlenenTEdit.Create(IzlenecekBilesen)
else if IzlenecekBilesen.ClassName = ‘TCheckBox’ Then
fObje :=TIzlenenTCheckBox.Create(IzlenecekBilesen)
else if IzlenecekBilesen.ClassName = ‘TComboBox’ Then
fObje :=TIzlenenComboBox.Create(IzlenecekBilesen)
else if IzlenecekBilesen.ClassName = ‘TSpinEdit’ Then
fObje :=TIzlenenTSpinEdit.Create(IzlenecekBilesen);

if Assigned(fObje) then
fListIzlenenBilesenler.Add(fObje);

end;

//listeden bilesen cikartmak icin….
//listeyi tamamen taramak guzel bir cozum degil gibi ama simdilik bir problem yok ;) procedure TIzleyici.IzlenecekBilesenSil(SilinecekBilesen: TControl);
var
i:integer;
begin

for i:=0 to fListIzlenenBilesenler.Count - 1 do
if fListIzlenenBilesenler.Count >= (i + 1) then
if (fListIzlenenBilesenler.Items[i] as TAbstractIzlenenBilesen).GetIzlenenBilesenName = SilinecekBilesen.Name Then
fListIzlenenBilesenler.Delete(i);
end;

//izlenen bilesenlerde bir degisiklik var mi?
//listedeki siniflar TAbstractIzlenenBilesen’inden turediginden ve
//IzlenenBilesendeDegisiklikVarMi metodu soyut oldugundan tek donguyle hepsini
//kontrol edebiliyorum. sihir mi demek lazim yoksa gec baglamami size birakiyorum :) function TIzleyici.BilesenlerdeDegisiklikVarMi: Boolean;
var
i:integer;
begin
Result :=False;
for i:=0 to fListIzlenenBilesenler.Count - 1 do
Result := Result or (fListIzlenenBilesenler.Items[i] as
TAbstractIzlenenBilesen).IzlenenBilesendeDegisiklikVarMi;
end;

şimdi uygulamaya geçelim.

formun createinde izlemek istedigimiz bilesenleri listeye ekliyoruz.

procedure TForm1.FormCreate(Sender: TObject);
begin
Izleyici:=TIzleyici.Create;
Izleyici.IzlenecekBilesenEkle(Edit1);
Izleyici.IzlenecekBilesenEkle(CheckBox1);
Izleyici.IzlenecekBilesenEkle(ComboBox1);
Izleyici.IzlenecekBilesenEkle(SpinEdit1);
end;

//kaybol ortaliktan :) procedure TForm1.FormDestroy(Sender: TObject);
begin
FreeAndNil(izleyici);
end;

Kullanici ilgili bilesenleri kurcalamis mi? bu sorunun cevabi iste bu kadar basit

procedure TForm1.Button1Click(Sender: TObject);
begin
if Izleyici.BilesenlerdeDegisiklikVarMi Then
ShowMessage(’Değişiklik var’)
else
ShowMessage(’Değişiklik yok’)
end;

Listeden bir bilesen cikarmak isterseniz

procedure TForm1.Button4Click(Sender: TObject);
begin
Izleyici.IzlenecekBilesenSil(ComboBox1);
end;

iste size gayet temiz ve test edilebilir bir cozum.

Ornek koda burdan ulasabilirsiniz.

dosyayi buraya upload edemedim. burdan yetkililere sesleniyorum :)

not: rar dosyasinda birim testleri de mevcut. onlarida ileriki zamanlarda buraya koymayi dusunuyorum aciklamali olarak…

not 2: merakli arkadaslara bir hatirlatma.
TComboBox in testlerinde bi problemi asamadim. runtime de comboboxi olsuturup item ekleyemedim. test sonucu hep hata uretiyor.

neyse simdilik kaciyorum. daha bulasik yikayip sahur icin biseler hazirlamam lazim. kola + ekmek ve peynir gibi…

Leave a Reply