Konuyu Oyla:
  • Derecelendirme: 5/5 - 4 oy
  • 1
  • 2
  • 3
  • 4
  • 5
Interposer Class Nedir, Nasıl Kullanılır
#1
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;


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.

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.

Faydalı olması dileğiyle,
YouTube Delphi Tips
"Yaşlanarak değil, yaşayarak tecrübe kazanılır. Zaman insanları değil, armutları olgunlaştırır" Peyami Safa
WWW
Cevapla
#2
Emeğinize sağlık.

Sadece küçük bir hatırlatma:  TPanel.Destroy'da FreeAndNil(FButon)'a gerek. Zira; siz zaten butonu Create ederken Self parametresi ile Butonun sahibinin Panel olduğunu belirtiniz:
FButon := TButton.Create(Self);

Panel Destroy olduğunda FButton da destroy olacaktır. Yani TPanel'in destructor'unı yeniden tanımlamaya gerek yok.
There's no place like 127.0.0.1
WWW
Cevapla
#3
Haklısınız gerek yok fakat bu benim bir prensibim haline gelen bir durum, yani ben oluşturduysam mutlaka ben yok etmeliyim.
YouTube Delphi Tips
"Yaşlanarak değil, yaşayarak tecrübe kazanılır. Zaman insanları değil, armutları olgunlaştırır" Peyami Safa
WWW
Cevapla
#4
Değerli katkılarınızdan dolayı teşekkür ederim.
Cevapla
#5
Zaman ayırıp böyle bir şeyi paylaştığınız için teşekkürler elinize sağlık
Bu dünyada kendine sakladığın bilgi ahirette işine yaramaz. 
Cevapla
#6
Elinize saglik
Cevapla
#7
Bu tarz yazıları görünce hiç birşey bilmediğimi görüp bilmem gereken çok şey olduğunu düşünmeye başlıyorum. Meraklanıp araştıyorum uykum kaçıyor uyuyamıyorum. Allahtan profesyonel yazılımcı Değilim. Yoksa neler olur bilemiyorum. Elinize sağlık Smile
Cevapla
#8
Makale için teşekkkürler, elinize sağlık. Bu yöntemi benim de kullandığım oldu.
Bu yöntemi kullanmak isteyenler için ufak bir not düşmek isterim. Bu yöntem bir yöntem olmaktan ziyade minik bir hiledir. Nesneye dayalı yazılımda böyle bir yöntem kesinlikle tavsiye edilmez. Gerçekten başınız sıkışırsa kullanmalısınız.
WWW
Cevapla
#9
Teşekkür ederim, @sadettinpolat , siz "hile" deyince Marco Cantu'nun "Object Pascal Handbook" (temmuz 2015 baskısı) adlı kitabı aklıma geldi. Sayfa 320, 321 ve 322'de bu konuya değinmiş ve Adaptör Design Pattern başlığı altında bu konuda da bir örnek vermişti. Buradan benim anladığım bu hilenin bir şekilde Delphi kanadında destek bulduğu ve hala kullanabiliyor olduğumuz yönünde. İstemeselerdi veya desteklemeselerde bu hileyi bir şekilde kapatma yolunu izleyebilirlerdi zira 1998'den beri bilinen bir konu. O nedenle ben bu noktada pek çekimser değilim, yani yeri geldiğinde kullanılmasında sakınca görmüyorum.
YouTube Delphi Tips
"Yaşlanarak değil, yaşayarak tecrübe kazanılır. Zaman insanları değil, armutları olgunlaştırır" Peyami Safa
WWW
Cevapla
#10
Eline sağlık. Oldukça hoş.

Ama ben yine de olabildiğince class helper benzeri klasik programlama standartlarını kullanmayı tercih ederim.

Tüm kod içinde değişiklik yapmaya da razıyım tabi.
Cevapla


Konu ile Alakalı Benzer Konular
Konular Yazar Yorumlar Okunma Son Yorum
  SANAL BİLGİSAYARA macOS SONOMA NASIL KURULUR? engerex 1 235 19-02-2024, Saat: 08:41
Son Yorum: yhackup
  OOP : Polymorphism, Inherited Class uparlayan 19 10.559 14-05-2021, Saat: 22:46
Son Yorum: SimaWB
  Kendi Logaritma Fonksiyonumuzu Nasıl Yazarız? savasabd 4 3.220 10-03-2020, Saat: 22:50
Son Yorum: savasabd
  IF Nedir, Nasıl Kullanılır uparlayan 14 16.129 13-12-2019, Saat: 09:23
Son Yorum: SimaWB
  Array Nedir, Nasıl Kullanılır (Güncellendi) uparlayan 11 16.446 26-09-2019, Saat: 11:43
Son Yorum: Bay_Y



Konuyu Okuyanlar: 1 Ziyaretçi