Interposer kelimesinin karşılığı aracı, aracılık yapan demektir. Yani başlık aslında "Aracı Sınıf Nedir" şeklinde de yazılabilirdi.
Bir Interposer Sınıfı, (hiyerarşik anlamda konuşacaksak) bir sınıfın (kendisinden türediği) bir ata sınıf ile bu sınıfın türüne ait bir nesnenin beyanı arasında konumlandırılış bir "Aracı sınıftır". Ana karakteristiği, ata sınıf ile aynı isme sahip olmasıdır. Bu sayede uygulamalarda ata sınıfın kullanıldığı durumlarda süreci basitleştirmek hedeflenmiştir. Bu teknik aslında 1998'den beri var ve Delphi ile yeteri kadar haşırneşir olanların çok sık kullandığı bir teknik diyebilirim.
Bunu bir hikaye üzerinden açıklamaya çalışayım; Mesela, diyelimki bir uygulamanız var ve bu uygulamanızın bir çok yerinde TPanel nesnesini kullanmışsınız. Bir vakit sonra sizden istisnasız, bu uygulamadaki tüm panellerin sağ üst köşesine bir kapatma butonu koymanız isteniyor ve size deniliyor ki; "Kardeş, biz bu kapatma butonunu koyuyoruz ama kullanıcılar bunu beğenmezse bu talepten vaz da geçebiliriz" diyorlar... Al bakalım, sakal mı bıyık mı! Bu problemi nasıl çözeriz?
Normalde böyle bir durumda tasarım ekranını açıp tüm TPanel nesnelerinin sağ üst köşesine tek tek buton ekler ve içine de ilgili kodu yazarsınız. Peki, güzel... Ya projenizde form sayısı onlarca, hatta yüzlerceyse, o zaman ne olacak? Tüm bu TPanellere aynı işlemi tek tek yapmak bariz bir şekilde hamallık değil de nedir?
Bazı arkadaşlar "Class Helper" tekniğine başvurmak isteyebilir ama hepimiz biliyoruz ki Sınıf Yardımcıları sadece yardım ettikleri sınıfın yerel değişkenleri ve property'leri üzerinde işlem yapabiliyor, asıl nesnenin private bölümündeki değişkenlere erişimde sıkıntı yaşatıyor. Ayrıca Class Helper'larda yeni bir değişken tanımlayamazsınız asıl sınıfın mevcudunda olanları kullanmak durumundasınız. Interposer Class ile Class Helper arasındaki bu temel fark sizin Class Helper veya Interposer Class arasındaki tercihinizi etkiler... Dolayısıyla şimdiki senaryoya uymayan bir durum olduğu için bu noktada class helper tekniği kullanışlı bir seçenek değildir...
Diğerleri de "TPanel'den türetilmiş başka bir tip tanımlarız" diyebilir, yine de tüm formları tek tek gezmeniz ve ilgili eşleşmeleri tek tek düzeltmeniz gerekir. Yani sonuç olarak yine dönüp dolaşıp bu hamallık sekansına geri geliyoruz...
Bunun daha basit bir çözümü yok mu? Yani bu hamallıktan kurtulamayacak mıyız? Hamallıktan kurtuluş yok ama yükümüzü buzdolabı ölçeğinden, aspirin kutusu ölçeğine kadar küçültebiliriz...
İşte bunun gibi durumlarda sizden "YAPISAL OLARAK" mevcut bir şeyi değiştirmeniz isteniyorsa bu noktada devreye Interposer sınıflar giriyor. Peki bu Interposer Sınıf denen şey tam olarak nedir? Cevap basit: Aslında, sınıfın kendisini yine kendisinden türetmektir diye özetleyebiliriz.
Yukarıdaki senaryoyu ele alacak olursak yine o çerçevede bir örneklendirme yapalım.
Yapacağımız şey çok basit, projemizdeki tüm TPanel nesnelerinin sağ üst köşesine bir buton koyacağız ve bu butona basıldığında TPanel nesnesi kendisini imha edecek. Normalde böyle bir özellik TPanel nesnesinde yok ve bizden bu özellik projedeki tüm TPanel nesnelerinde olsun isteniyor...
Bunun için adı InterposerObjects adlı boş bir unit oluşturuyoruz ve içini aşağıdaki gibi dolduruyoruz. Açıklamalar ise kod içinde devam ediyor;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
unit InterposerObjects; interface uses Vcl . StdCtrls // TButton , System . Classes // TComponent , Vcl . Controls // Anchors , Vcl . ExtCtrls // TPanel normalde bu unit'te tanımlıdır. Biz bu unitteki TPanel'e yeni bir özellik ekleyeceğiz aşağıda... ; type TPanel = class (Vcl . ExtCtrls . TPanel) // Bu bizim INTERPOSER sınıfımız oluyor. private FButon: TButton; // Gerçek sınıfta olmayan bir buton nesnemiz var protected procedure PaneliYokEt(Sender: TObject); // Yine Gerçek sınıfta olmayan bir olay tanımlıyoruz. // Bunun görevi paneli yok etmek olacak... public constructor Create(AOwner: TComponent); override; // Butonumuzu bu noktada oluşturuyoruz... destructor Destroy; override; // Butonumuzu bu noktada yok ediyoruz... end ; implementation uses System . SysUtils , Vcl . Dialogs ; { TPanel } constructor TPanel . Create(AOwner: TComponent); begin // Bu kısım inheritance / miras alma yoluyla klasik TPanel'de ne varsa onu zaten üretiyor. inherited Create(aOwner); // Bu noktadan sonrasında ise geliştirdiğimiz sınıfımızda yeni butonumuzu yerleşik olarak oluşturuyoruz FButon := TButton . Create(Self); with FButon do begin Parent := Self; Width := 20 ; Height := 20 ; Caption := 'xx' ; Top := 0 ; Left := Self . Width - 20 ; Anchors := [akTop, akRight]; OnClick := PaneliYokEt; end ; end ; destructor TPanel . Destroy; begin // Önce yeni butonumuzu yok ediyoruz FreeAndNil(FButon); // sonra yine miras yoluyla klasik yok etme prosedürünü çağırıyoruz... inherited Destroy; end ; procedure TPanel . PaneliYokEt(Sender: TObject); begin ShowMessage( 'INTERPOSER SINIF aracılığıyla böyle bir yetenek kazandırmış olduk...' ); Destroy; // ve TPANEL kendi kendini yok eder... end ; end . |
Bu noktadan sonra ise yapacağımız tek bir şey var. Bu uniti projedeki tüm pas dosyalarının INTERFACE bölümüne eklemek olacak. Yalnız burada dikkat etmemiz gereken bir nokta var o da şu, normalde TPanel "Vcl.ExtCtrls.pas" dosyasında tanımlıdır, biz ise kendi unitimizi bu unitten hemen sonra eklemeliyiz yoksa yaptıklarımız bir işe yaramaz.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
unit Ana_; interface uses Winapi . Windows, Winapi . Messages , System . SysUtils, System . Variants, System . Classes , Vcl . Graphics, Vcl . Controls, Vcl . Forms, Vcl . Dialogs , Vcl . StdCtrls , Vcl . ExtCtrls // TPanel normalde bu unit'te tanımlıdır... , InterposerObjects // YAPMAMIZ GEREKEN İSE SADECE BU UNİTİ BURAYA EKLEMEKTİR... ; type TForm2 = class (TForm) Panel1: TPanel; private { Private declarations } public { Public declarations } end ; var Form2: TForm2; implementation {$R *.dfm} end . |
Tasarım ekranında görmeseniz bile projenizi çalıştırdığınızda gördüğünüz her TPanel nesnesinin sağ üst köşesinde bir kapatma butonuna sahip olduğunuzu göreceksiniz.
https://www.delphican.com/showthread.php?tid=2602 adresinden alınmıştır.
Faydalı olması dileğiyle,