Prototype Pattern

Karmaşık ve/veya pahalı sınıflardan nesne yaratırken, yeni nesnelerin baştan yaratılması yerine, mevcutlarından örnekleyerek yaratılmasını sağlar. Bu sayede yeni nesneler kolayca ve kaynaklar gereksiz yere meşgul edilmeden yaratılırlar.

clon.gif

dogruyu soylemek gerekirse bu kalipla cozum getirilen -getirilmek istenen- problemle ben henuz karsilasmadim. daha dogrusu bir bileseni -nesneyi- kopyalamak ihtiyaci henuz hissetmedim. en azindan yazmaya calistigim uygulamalarda boyle bir seye ihtiyac olmadi ama ne tur uygulamalarda ise yarayabilecegi cok acik bir sekilde goruluyor. mesela elektronik devrelerin cizildigi bir uygulama yaziyorsaniz isinize cok yarayacagina eminim. kullanicinin form uzerine koydugu ve bir cok ozelligini degistirdigi bir devre elemani dusunun. Daha sonra bu devre elemaninin aynisindan bir tane daha olusturmak istedi. Yapacagi islem forma bir tane daha yeni devre elemani ekleyip ozelliklerini degistirmek olmayacaktir. daha onceden olusturmus oldugu devre elemanini secip ctrl+c yapip ardindan ctrl+v ile bu yeni elemani forma yapistirmak ve farkli olan degeri degistirmek olacaktir. Bu gibi bir durumda sizin yapacaginiz is su olabilir. Secili nesnenin sinifindan yeni bir nesne create etmek ve eski nesnenin butun ozelliklerini yeni nesneye teker teker kopyalamak. ilk basta makul bir cozum gibi duruyor olabilir ama hem bir nesneyi create etmek masrafli bir islemdir hem de nesnelerin birbirlerinden farkli bir cok ozelligi oldugu icin duzgun ve sorunsuz bir kopyalama islemi yapmak oldukca zordur. bu nedenle nesnelerin klonlanmasi daha makul bir cozumdur. gerci delphi orneginde nesne yeniden create ediliyor (create etmeden bir nesneyi olusturmak mumkun mudur?) ama diger bilgileri -eski bilesenin adina bile el koyar :) - aynen eski bilesenin bilgilerinden aldigi icin bizim bu isle ugrasmamiz gerekmiyor.

java da ve .net te bu islemi gerceklestirmek icin daha basit yollar mevcut ama gordugum kadariyla delphi tarafinda bu is biraz zor. ustelik bu ornek sadece TComponent sinifini ve haleflerini clonlayabilir.

Clonlama isi icin delphinin 3 ozelliginden yararlanmamiz gerekiyor.

1- class referanslari
2- stream sinifi
3- rtti

Delphinin TCompenent sinifindan turemis butun nesneleri diske yazma (WriteComponent) ve bu bilgileri tekrar diskten okuma (ReadComponent) ozelligi var. Clonlamak istedigimiz bir bilesenin bilgilerini ilk once bir memory streame yazdirip ardindan bu bilgileri yeniden okuyarak yeni olusturdugumuz nesneye aktarıp clonlama isini yapmis olacaz.

birazdan gorecegimiz ornegi marco cantu dan odunc aldim. kendimce eksik gordugum bazi yerleri degistirerek biraz degistirdim. hatta icerisinde baska bilesenler barindiran (panel gibi) bilesenleri icindeki bilesenlerle beraber clonlayan yeni bir surumunude yazdim.

ilk once basit olan surumu gorelim.

function Clone (c: TComponent): TComponent;

bu fonksiyon kendisine parametre olarak gecilen nesneyi clonlar ve geriye donderir.

function Clone (c: TComponent): TComponent;
var
mStream: TMemoryStream;
OldParent :TWinControl;
cIsTControl:Boolean;
begin

assert(c nil,’olmayan nesnenin nesini clonluyon bilader?’);

OldParent :=Nil;
cIsTControl := c is TControl;

if cIsTControl then
OldParent := (c as TControl).Parent;

mStream := TMemoryStream.Create;
try
mStream.WriteComponentRes (c.Name, c);
mStream.Position := 0;
c.Name := c.Name + IntToStr (sayi);
Result := TComponentClass(c.ClassType).Create (c.Owner);
mStream.ReadComponentRes (Result);
inc(sayi);

if cIsTControl then
(Result as TControl).Parent :=OldParent;

finally
mStream.Free;
end;
assert(c Result,’bu iste bi hata var’);
end;

simdilik ilk satirlari atlayip mStream := TMemoryStream.Create; satirina gelmek istiyorum. bu satir bileseninin tum ozelliklerini kaydebilmemiz icin bir adet memory stream olusturur. ardindan WriteComponentRes metoduyla parametre olarak verdigimiz bileseni kaynak dosya formatinda (resource file) hafizaya yazar.

bir isim cakismasi olmasin diye c.Name := c.Name + IntToStr (sayi); satiri ile kopyasini cikardigimiz bilesene yeni bir isim verilir. burda bilmeniz gereken kopyasini cikardigimiz bilesenin adini degistirdigimiz. bu kod orjinal nesnenin adini clonlama sonucu olusan -dogal olarak- nesneye atar. eger siz kopyasini cikardimiz bilesenin adinin orjinal halinde kalmasini istiyorsaniz kodda ufak degisiklikler yapmaniz gerekir.

Result := TComponentClass(c.ClassType).Create (c.Owner); satirinda ise class referansi kullanilarak ilgili nesnenin bir ornegi olusturulur.

mStream.ReadComponentRes (Result); satiri ise yeni olusturulan nesneye orjinal nesnenin tum bilgilerini aktarir.

kodun orjinal halinde parent ozelligi bu fonksiyonun disinda ataniyordu. fonksiyonun disinda atanma sebesi ise bu fonksiyonun tum TCompenent sinifindan tureyen nesneleri klonlayabilmesidir ama Parent ozelligi sadece TControl ve haleflerinde olan bir ozelliktir. Mesela TTable gibi bilesenlerin parent ozelligi yoktur. her TControl sinifi icin bu degeri ayri ayri atamaktansa tip kontrolu yaparak uygun yerde bu degeri fonksiyon icinde atamayi uygun gordum.

OldParent :=Nil;
cIsTControl := c is TControl;

if cIsTControl then
OldParent := (c as TControl).Parent;




if cIsTControl then
(Result as TControl).Parent :=OldParent;

satirlari bu isi yapar….

Simdi bir editi clonlamak isterseniz bu satiri yazmaniz yeterlidir.

Clone(Edit1);

edit1′in sadece adi disinda tum ozellikleriyle birebir kopyasini elde edebilirsiniz.

ayni sekilde bir statusbari da clonlayabilirsiniz.

Clone(StatusBar1);

table1 icin de Clone (Table1) yazabilirsiniz.

bu metodun kotu yani sadece bir bileseni kopyalamasidir. ya icinde baska bilesenler barindiran nesneleri clonlamak istersek ?

bunun icin varolan metodu biraz degistirmek veya bu tip durumlar icin yeni bir metod tanimlamak gerekebilir. ben ayni ada sahip asiri yuklenmis(!) bir metod yazmayi tercih ettim. bu metod icice olan butun bilesenleri tarar ve hepsinin bir kopyasini olusturur.

function Clone (c: TComponent;NewParent:TWinControl): TComponent;overload;

metodun govdesi….

function Clone (c: TComponent;NewParent:TWinControl): TComponent;
var
mStream: TMemoryStream;
OldParent :TWinControl;
cIsTControl:Boolean;
j:byte;
begin
assert(c nil,’olmayan nesnenin nesini clonluyon bilader?’);
OldParent :=NewParent;

cIsTControl := c is TControl;

if cIsTControl then
if OldParent = nil then //orjinal nesnenin parentini kullan
OldParent := (c as TControl).Parent;

mStream := TMemoryStream.Create;
try
mStream.WriteComponentRes (c.Name, c);
mStream.Position := 0;
c.Name := c.Name + IntToStr (sayi);
Result := TComponentClass(c.ClassType).Create (c.Owner);
mStream.ReadComponentRes (Result);
inc(sayi);

if cIsTControl then
(Result as TControl).Parent :=OldParent;

finally
mStream.Free;
end;

if (c is TWinControl) and ((c as TWinControl).ControlCount > 0) then
for j:=0 to (c as TWinControl).ControlCount -1 do
Clone((c as TWinControl).Controls[j] ,result as TWinControl)
//barindirdigi her nesne icin clone metodunu yeniden cagir.

assert(c Result,’bu iste bi hata var?’);
end;

ornegi indirmek icin tiklayin.

prototype.jpg

not: diger kalip orneklerine simdilik http://sadettinpolat.zaxaz.com/?cat=8 bu adresten ulasabilirsiniz.

11 Responses to “Prototype Pattern”


  1. 1 cemaliozan

    ne gadder eglenceli olmuş. Eline zihnine sağlık. Hocam böyle çılgın kodlar yazmayın ya delphiye olan hakimiyetimi sorgulamaya başladım. Bu yüzden baştan delphi çalışasım geliyor. :)

  2. 2 Furkan Duman

    Böyle yapacağımıza niye doğrudan Assign etmiyoruz ki? TPersistent sınıfı bunun için yazılmış. TComponent te TPersistent’ten türemiş.

    Bir de bildiğim kadarıyla TComponent nesnesinin sadece published property’lerini diske yazıp geri okuyabiliyoruz. Hatalı olabilirim. Düzeltin lütfen.

    Ben eğer kopyalama ihtiyacı hissedeceğim bir bileşen oluşturuyorsam, TPersistent veya TComponent’ten türetiyorum.

  3. 3 Tuğrul

    Sevgili Furkan, O zaman her kopyalamak istediğin sınıf için Assign metodunu ezmelisin.Varsayılan olarak ezilmemiştir. Mesela TEdit nesnelerini kopyalayacaksan eğer TEdit sınıfı içerisinde yada kendi yazdığın TEdit’i miras almış bir sınıf içerisinde Assign’ı ezmelisin(override). Aksi taktirde VCL senin sınıfında nelerin kopyalanması gerektiğini bilemeyecektir.

    Bir diğer husus ise akış sistemi evet varsayılan olarak sadece published property’leri yazar ve okur. Ancak bu davranışı değiştirebilirsiniz. DefineProperties ile ;)
    Saygılar, sevgiler..

    Tuğrul HELVACI

  4. 4 ali usta

    Valla Sadettin’in kodlarını ve yazılarını okudukça delphi öğrenesim geliyor : )

  5. 5 sadettinpolat

    @ali usta, tesekkur ediyorum. bu ogrenme tutkusu sizin ogrenme azminizden ileri geliyor efenim :) saygilar…

  6. 6 sadettinpolat

    himm, assign olayini bende denemistim ama basarili olamamstim. nedenini @tugrul belirtmis. ogrenmis oldum.

  7. 7 thelvaci

    Sadettin şu .Net ile ilgili önerime ne diyorsun destek verde başlayalım şu işe.

    Saygılar, sevgiler..
    Tuğrul HELVACI

  8. 8 sadettinpolat

    tugrul kardes su an hayatimda bazi koklu degisiklikler oldugundan bilgisayarimdan uzak gurbet ellerdeyim. bu aralar bloga da yorum disinda bir katkim olacagini pek sanmiyorum. kisa bir sureligine affinizi istiyorum…

  9. 9 Tuğrul

    Allah hayatındaki değişiklikleri kolay ve hayırlı etsin.

    Saygılar,sevgiler..
    Tuğrul HELVACI

  1. 1 soyle bir toparlanin bakayim ! at Delphi Blog (Türkçe)
  2. 2 soyle bir toparlanin bakayim ! at Sadettin POLAT

Leave a Reply