Hoşgeldin, Ziyaretçi
Sitemizden yararlanabilmek için Kayıt olmalısınız.

Kullanıcı Adınız:
  

Şifreniz:
  





Forumda Ara

(Gelişmiş Arama)

Forum İstatistikleri
» Toplam Üyeler: 1.162
» Son Üye: cascaridas
» Toplam Konular: 2.377
» Toplam Yorumlar: 18.887

Detaylı İstatistikler

Son Aktiviteler
Derleyici Direktifleri Ha...
Forum: Genel Programlama
Son Yorum:

ssahinoglu
9 saat önce
» Yorumlar: 7
» Okunma: 3.020
Kimler ne yapıyor?
Forum: Muhabbet Olsun
Son Yorum:

dicle_gsm
Dün, Saat: 12:29
» Yorumlar: 1
» Okunma: 74
Kayan Yazı
Forum: Genel Programlama
Son Yorum:

ssahinoglu
Dün, Saat: 08:49
» Yorumlar: 48
» Okunma: 2.525
Yazarken Dinlediğiniz Müz...
Forum: Muhabbet Olsun
Son Yorum:

dicle_gsm
20-08-2018, Saat: 23:15
» Yorumlar: 50
» Okunma: 18.107
Http post etme
Forum: Genel Programlama
Son Yorum:

arsl01
20-08-2018, Saat: 19:59
» Yorumlar: 0
» Okunma: 39
Iyi bir ide'nin avantajı ...
Forum: Muhabbet Olsun
Son Yorum:

masteryoda
20-08-2018, Saat: 17:17
» Yorumlar: 6
» Okunma: 96
Delphi Udemy Kursu
Forum: Görsel Eğitimler
Son Yorum:

hyperxman
20-08-2018, Saat: 16:16
» Yorumlar: 26
» Okunma: 746
Delphican Ailesinin Kurba...
Forum: Muhabbet Olsun
Son Yorum:

berk06
20-08-2018, Saat: 10:33
» Yorumlar: 12
» Okunma: 158
Mobil platform örnekleri
Forum: e-Kaynak
Son Yorum:

hyperxman
19-08-2018, Saat: 01:28
» Yorumlar: 3
» Okunma: 91
Listview tedit
Forum: Mobil Platform - FireMonkey (FMX)
Son Yorum:

narkotik
17-08-2018, Saat: 20:31
» Yorumlar: 2
» Okunma: 81

 
Question Unigui UnimDBGrid1 Dinamik Yapı
Yazar: elixir84 - 14-08-2018, Saat: 10:08 - Forum: Delphi ile Web Teknolojileri - Yorum Yok

Merhaba,

Unigui de Touch (mobil) kısmında dinamik DBGrid yapmak istiyorum. Yani Query göre UnimDBGrid1 Column ları oluşacak ve bunlara autofit özelliği verilecek. 

Hiç bişey yapamadan Datasource bağlayınca listeleniyor ama columnlara autofit özelliği veremedim. Yada columnlara Width değerlerini kodla verebiliyormuyuz. Bunu Unigui Touch (mobil) kısmında yapmaya çalışıyorum.


Çok özür dileyerek şöyle bir kod buldum..

procedure FitGridColumns(Grid: TUnimDBGrid; theForm:TUnimForm);
const
 C_Add=3;
var
 ds: TDataSet;
 bm: TBookmark;
 i: Integer;
 w,tw, ShortestLength: Integer;
 a: Array of Integer;

 Function GetTheTextWidth(StrIn:String):Integer;
 var c: TBitmap;
 Begin
    Result := 0;
    c := TBitmap.Create;
    try
      c.Canvas.Font.Name := theForm.Font.Name;
      c.Canvas.Font.Size := theForm.Font.Size+2;
      Result := c.Canvas.TextWidth(StrIn);
    finally
      c.Free;
    end;
 End;

begin
 ds := Grid.DataSource.DataSet;
 if Assigned(ds) then
 begin
   bm := ds.GetBookmark;
   try
     if Grid.Columns.Count = 1 then
     Begin
       Grid.Columns[0].Width := grid.Width;
     End
     Else
     Begin
       if ds.RecordCount > 0 then
       Begin
         ds.First;
         SetLength(a, Grid.Columns.Count);
         while not ds.Eof do
         begin
           for I := 0 to Grid.Columns.Count - 1 do
           begin
             if Assigned(Grid.Columns[i].Field) then
             begin
               tw := GetTheTextWidth(Grid.Columns[i].Title.Caption)+40;
               w :=  GetTheTextWidth(ds.FieldByName(Grid.Columns[i].Field.FieldName).DisplayText)+40;

               if w < tw then
                 w := tw;

               if a[i] < w  then
                  a[i] := w ;
             end;
           end;
           ds.Next;
         end;
         for I := 0 to Grid.Columns.Count - 1 do
         Begin
           Grid.Columns[i].Width := a[i] + C_Add;
         End;
       End
       Else
       Begin
         for I := 0 to Grid.Columns.Count - 1 do
         begin
           Grid.Columns[i].Width := GetTheTextWidth(Grid.Columns[i].Title.Caption)+40;
         end;
       End;
     End;
     ds.GotoBookmark(bm);
   finally
     ds.FreeBookmark(bm);
   end;
 end;
end;

Bu konuyu yazdır

  Yurtdışına açılmak için izlememiz gereken yollar.
Yazar: csunguray - 13-08-2018, Saat: 18:52 - Forum: Muhabbet Olsun - Yorumlar (29)

Uzun zamandır böyle bir başlık açmak istiyordum. Dolar ve Avro'nun fırlamasıyla bu konu daha da önem kazandı.

Eğer bir takım ürünler geliştirip buradaki müşterilerimize satabiliyorsak (yani onlar için faydalı olabiliyorsak) aynı şeyi Almanya'daki bir Alman (veya Türk), İtalya'daki bir İtalyan vb. için de yapabiliriz. Çünkü burada (atıyorum) 1.000 TL'ye sattığımız ürünü Avrupa pazarında yaklaşık 1.000 Avro'ya satma şansımız var.

Bunu yapabilmek için izlememiz gereken yollar, kazanmamız gerek yetenekler, ürünlerimizde yapacağımız değişiklikler ve sahip olmamız gereken bakış açıları ne olmalıdır? Bu konuda fikirlerinizi belirtirseniz faydalı olacağına inanıyorum.

Bu konuyu yazdır

  Sizce bu bir BUG'mıdır ?
Yazar: Tuğrul HELVACI - 13-08-2018, Saat: 14:21 - Forum: Genel Programlama - Yorumlar (19)

Senaryo:


  1. MDI bir uygulamanız var.
  2. Uygulamanızda birden fazla MDI Child formunuz var ve bu formlardan bir kısmı bir t anında ekranda görünür durumda ve bu formlarınızın OnCloseQuery olayında bir kısım kodlar var.
  3. Ana formunuzun OnCloseQuery olayında da bir kısım kodlar var.
  4. Kullanıcı uygulamanızı kapatmak istiyor.
Mevcut durumda şöyle oluyor:
  1. Tüm MDI Child formların OnCloseQuery olay yöneticileri tetikleniyor.
  2. En son ana formunuzun OnCloseQuery olay yöneticisi tetikleniyor.
Bu bir nesnenin sahibi olduğu nesneleri yok etmesi mantığında olduğu gibi işliyor. Ancak olması gereken bu mu acaba ? Bana kalırsa kullanıcı ana formun OnCloseQuery olayına bir kod yazdı ise, önce o kod çalıştırılmalı ardından CanClose değişkeni üzerinde varsayılan değerden farklı bir değer ataması yapıldı ise, mdi child pencerelerinde OnCloseQuery olayı çağrılmalı. Yani kullanıcı merkezi bir noktadan "Uygulamadan çıkmak istiyor musunuz ?" gibi bir soru sordu ise bunun cevabını beklemeden tüm pencerelere gitmek ve kapanabilirmiyim diye sormak pek makul görünmüyor. Çünkü kapanıp kapanmama kararı kullanıcıya sorulmak isteniyor.

Burada ise tam tersi bir durum söz konusu. Önce çocuk formların OnCloseQuery metodları çağrılıyor ve tüm CanClose'lar true ise, ana formun OnCloseQuery olayı tetikleniyor.

Sizin fikriniz nedir ?

Bu konuyu yazdır

  Ekonomik müdahalede silahsız bir savaşsa ilegal yolla yazılım kullanmak hak mı ?
Yazar: boreas - 13-08-2018, Saat: 10:35 - Forum: Muhabbet Olsun - Yorumlar (21)

Bugüne kadar olabildiğince illegal yolla yazılım kullanmamaya özen gösterdim ve bu tür bir yazılım kullanmanın hak olmadığını düşündüm. Ama şu son günlerde olan olaylarla, giden onlarca emekle bu adamların 10$ programına bile para vermek içimden gelmiyor hatta şeytan diyor en lüksünü kır kullan. Ama adı üstünde şeytan diyor Smile Sizler  ne düşünüyorsunuz merak ettiğim için açtım konuyu. 
Herkese kolay gelsin Smile

Not: Konuyu paylaşım amaçlı açmadım bilginize.

Bu konuyu yazdır

  Seçilmeyen satır
Yazar: ahmetb - 12-08-2018, Saat: 14:02 - Forum: Mobil Platform - FireMonkey (FMX) - Yorumlar (8)

Merhabalar,

Listview de "Selected.Index" ile satırların yerini değiştiriyorum. 
Başka satır seçmeme rağmen, değiştirdiğim satırın altındaki satırda seçilmiş gibi "Gri" oluyor. Çözüm için ne yapabilirim?




Linkleri Görebilmeniz İçin Giriş yap veya Üye Ol

Bu konuyu yazdır

  Focus
Yazar: ahmetb - 12-08-2018, Saat: 09:34 - Forum: Mobil Platform - FireMonkey (FMX) - Yorumlar (5)

Selamlar;

Listviewden delete ile satırı siliyorum. Kayıt silindikten sonra focus veya click durumunu isteğim satıra yapılmasını nasıl sağlarım? 

   

    if ItemObject.Name.Equals('Cikar') then
        begin
          iIndex := ItemIndex; // Seçilen satırın index numarası aldık
          Items.Delete(iIndex);
         ???
        end;

Bu konuyu yazdır

  FireBird Merge Into Kullanımı
Yazar: mcuyan - 11-08-2018, Saat: 21:08 - Forum: FireBird - Yorumlar (2)

Merhabalar arkadaşlar.

Bu kısa makalemde FireBird de Merge Into Kullanımını anlatacağım. (SQL de biraz zayıf olduğum için bu tür ilginç öğrenimlerimi sizlerle paylaşmak istemiştim.)

A tablosundaki kayıtları, verilen kritere uygun olarak B tablosundaki başka bir alana göre update edebilmek için merge into kullanılır.. 
A tablosundaki id ile B tablosundaki id eşleştiğinde, B tablosundaki ad ve soyad alanlarını A tablosundaki yerlerine yazar.


Kullanımı:

  merge into ATablosu a
  using BTablosu b
 on a.a_id=b.b_id
 when matched then
 update set
 a.a_ad=b.b_ad,
 a.a_soyad=b.b_soyad

Bu konuyu yazdır

  Dosyaları arama ve filtreleme aracı
Yazar: sabanakman - 11-08-2018, Saat: 16:34 - Forum: Hazır Programlar - Yorum Yok

İyi günler. Linkleri Görebilmeniz İçin Giriş yap veya Üye Ol isimli araç yüklendikten sonra 1-2 dk içinde sistemde bulunan ne kadar dosya ve klasör varsa bunları tespit edip, bu aşamadan sonra ürettiği listeyi kullanarak isimlerinden aramak ve filtrelemek için kullanıma hazır hale getirmektedir. Tabi anlık olarak oluşan veya silinen dosyaları da tespit edebilmektedir. Böylece tüm dosyalar üzerinden arama işlemi için böylesi hızlı çalışan bir uygulama bazen hayat kurtarıcı olabiliyor. 

Linkleri Görebilmeniz İçin Giriş yap veya Üye Ol
Linkleri Görebilmeniz İçin Giriş yap veya Üye Ol

İyi çalışmalar.

Bu konuyu yazdır

  Notification
Yazar: gonulali - 11-08-2018, Saat: 13:59 - Forum: Mobil Platform - FireMonkey (FMX) - Yorumlar (3)

Selamlar. 
Apk kurulu olan telefond veya tablette benim belirlediğim veya tetikleyeceğim zamanlarda notification çıkarmak istiyorum kullanıcının telefonunda. Bunu nasıl yapabilirim acaba? servismi yazılması gerek ?

Bu konuyu yazdır

  Tasarım Desenleri : Factory Method
Yazar: uparlayan - 10-08-2018, Saat: 20:06 - Forum: Makale - Yorumlar (8)

Tamamını elden geçirmektense sadece tek bir parametreyi değiştirerek projenizin mevcut davranışını yeniden düzenlemek veya ek davranışlar geliştirmek istediğiniz zamanlar oldu mu? "Biz zaten böyle şeyler yapabiliyoruz" dediğinizi duyar gibiyim... Kazın ayağı gerçekten de öyle mi acaba? Bu konuda birileri kafa yormuş...

Problem

Büyük veya gereğinden fazla şişmanlayan projelerin temel bir sorunu vardır: İyi planlanmamışsa zamanla dinamizmini kaybeder ve yavaş yavaş daha statik, daha hantal bir şekle bürünürler. Bazıları için bu pekde önemli bir konu olmayabilir fakat projeniz canlıysa ve yeni talepler gelmeye devam ediyorsa bu durum sizin için eziyet haline de dönüşebilir.

Diyelim ki, projenizde log tutmak için veritabanından faydalanıyorsunuz ve işin en başından beri loglama sürecini böyle planlamışsınız ve uzun zamandırda bu iş böyle yürümüş gitmiş... E güzel, log tutulabilecek her noktada bununla ilgili bigüzel kodlar da yazmışsınız... Sıkıntı yokmuş gibi gözüküyor değilmi, çünkü siz yapılması gereken herşeyi yapmış ve işleri rayına oturtmuşsunuz... Peki, tamam, günün birinde müşterinin teki log bilgilerinin kendisine Eposta ile bildirilmesini istedi diyelim. Veya bir başkası çıkıp "bana bu log bilgileri SMS ile gelsin", ya da başka bir müşteri "veritabanımı loglarla doldurmak istemiyorum, onun yerine client'lerde text dosyada tutulsun" gibisinden taleplerde bulundu diyelim... Bu durumda Projenizde değiştirmek zorunda olduğunuz bir davranış için bir çok noktayı elden geçirmek zorunda kalabileceğinizin farkında mısınız? Veya şöyle söyleyeyim; "Ya ne güzel, mutlu mesut loglarımı veritabanında tutuyordum, nereden çıktı bu abuk subuk istekler" diye düşünmeye başladınız belki de... İşte problemin kendisi aslında bu, yani koskoca projeyi tamamen elden geçirmek ve her noktasına müdahale etmek... Normalde çalışan ana kodunuza müdahale ediyorsanız bilin ki kökten yanlış bir şey yapıyorsunuz, çünkü bunun bir bedeli var. Halbuki bunun basit bir çözümü olabilir...

Çözüm

Herşeyden önce, bu tarz müşteri taleplerinin herzaman gelebileceğini önkoşul olarak zaten en baştan kabul etmiş olmanız gerekiyor... O nedenle işin proje yönetimi kısmına zaten değinmeyeceğim (ki konumuz da değil zaten) fakat teknik boyuta gelecek olursak; bu noktada literatür bize "Factory Method" (Fabrika Yöntemi) tekniklerini kullanmamız gerektiğini öneriyor...

Bu tasarım deseninin şöyle bir tanımı var; "Factory Method modeli, Sınıf Tabanlı programlamada oluşturulacak nesnenin, sınıfın kendisini doğrudan belirtmek zorunda kalmadan, nesne oluşturma sorunuyla başa çıkmak için, Factory Method zihniyetini kullanan bir üretim desenidir. Bu, bir arabirim tarafından çağrılan, bir arabirim tarafından belirtilen ve alt sınıflar tarafından uyarlanan (implemente edilen) veya bir temel sınıfta uygulanan ve istenirse türetilmiş sınıflara göre bir fabrika yöntemini çağırarak, bir kurucu çağırmak yerine, nesneler oluşturarak yapılır." diyor...

Yani biz bundan ne anlıyoruz? Özetleyecek olursak; işi yapacak olan fiili, gerçek nesneler ile işi talep edecek olan nesneler arasındaki bağlantıyı soyut bir sınıf veya (soyut) bir arabirim vassıtasıyla yapın. Böylece tür tipleri ve dönüşümleri ile uğraşmaktan, bir çok yerde IF blokları ile cebelleşmekten kurtulun...

Yani aslında buradan da anlaşıldığı üzere Factory Method'un temel amacı, değişkenlik gösterebilecek, zamanla farklı tekniklerin uyarlanabilmesini sağlayabilecek bir yapıyı barındırması nedeniyle yazılımlarımızda, kodlamalarımızda değişimi kontrol altına alabilmemizi sağlamaktır.

Nasıl?

Peki biz bunu nasıl yapacağız? Kavramın kendisi soyut olduğu için somut bir örnek üzerinden bu konuyu anlatmak herhalde daha uygun ve kolay olacaktır. Yazının en başındaki örnek üzerinden ilerleyelim isterseniz. Konunun daha iyi anlaşılabilmesi adına tasarım desenindeki bazı nesleleri belli unit'lerde toparladım, bu sayede tasarım desenini, iş nesnelerinizi ve ana uygulamanızı birbirinden daha kolay ayırdedebilmenizi hedefledim.

Önce arabirimlerimizi tanımlayalım;

unit FactoryPattern_Objects;

interface

uses
 Vcl.Dialogs;

type
 { Arabirimlerimizi tanımlıyoruz }
 ILogcu = interface                                           // Bu bizim log tutmak için kullanacağımız TEMSİLİ bir arabirim ( Soyuttur kendileri... )
    procedure Log(const aLog: String);                         // Bu da bizim log tutmak için kullanacağımız yine TEMSİLİ bir METODUMUZ ( Bu da soyut... )
 end;
 ILogFabrikasi = interface                                    // Bu bizim log fabrikası üretmek için kullandığımız TEMSİLİ bir arabirim ( Bu da soyut )
   function CreateLogcu: ILogcu;                              // Bu da bizim FACTORY METHOD ile kastettiğimiz fabrikamız... Olay aslında bunu tanımlamakla başlıyor...
 end;

 { LOGCU Sınıflarımızı tanımlıyoruz }
 TLogcu_SQL = class(TInterfacedObject, ILogcu)                // Bu SQL ile log tutan "GERÇEK" bir sınıf örneğimiz, arabirimimizi implemente edeceğimiz gerçek nesnelerden birisi bu olacak
   public
     procedure Log(const aLog: String);                       // Logu SQL'de tutacak olan "GERÇEK" bir metod. Bunun içinde fiilen SQL Scriptlerini çalıştıran bir kod olması gerekecek...
 end;
 TLogcu_SMS = class(TInterfacedObject, ILogcu)                // Bu SMS ile log tutan "GERÇEK" bir sınıf örneği, bunu da ILOGCU'dan türettik!
   public
     procedure Log(const aLog: String);                       // Logu SMS ile gönderecek olan "GERÇEK" bir metod. Bunun içinde fiilen SMS gönderen bir kod olması gerekecek...
 end;
 TLogcu_MAIL = class(TInterfacedObject, ILogcu)               // Bu da EPOSTA ile log tutan yine "GERÇEK" bir sınıf örneği, bunu da ILOGCU'dan türettik!
   public
     procedure Log(const aLog: String);                       // Logu EPOSTA ile gönderecek olan "GERÇEK" bir metod. Bunun içinde fiilen EPOSTA gönderen bir kod olması gerekecek...
 end;

 { FACTORY METHOD'larımızı tutan sınıfları tanımlıyoruz }
 TLogFabrikasi_SQL = class(TInterfacedObject, ILogFabrikasi)  // SQL için kullanacağımız loglama sınıfını üretecek olan fabrika sınıfımız
   public
     function CreateLogcu: ILogcu;                            // FABRİKA METODUMUZ, Dananın kuyruğunun koptuğu yerlerden birisi burası
 end;
 TLogFabrikasi_SMS = class(TInterfacedObject, ILogFabrikasi)  // SMS için kullanacağımız loglama sınıfını üretecek olan fabrika sınıfımız
   public
     function CreateLogcu: ILogcu;                            // FABRİKA METODUMUZ, Dananın kuyruğunun koptuğu yerlerden birisi de burası
 end;
 TLogFabrikasi_MAIL = class(TInterfacedObject, ILogFabrikasi) // EPOSTA için kullanacağımız loglama sınıfını üretecek olan fabrika sınıfımız
   public
     function CreateLogcu: ILogcu;                            // FABRİKA METODUMUZ, Dananın kuyruğunun koptuğu yerlerden birisi de burası
 end;

implementation

{ TLogcu_SMS }

procedure TLogcu_SMS.Log(const aLog: String);
begin
 ShowMessage('SMS ile loglama yapıldı: ' + aLog);
 // Burada SMS gönderen bir kod olduğunu varsayalım ve öyle düşünelim...
 // çünkü mevzu logun SMS ile nasıl gönderildiği değil...
 // ...
 // ...
end;

{ TLogcu_SQL }

procedure TLogcu_SQL.Log(const aLog: String);
begin
 ShowMessage('SQL ile loglama yapıldı: ' + aLog);
 // Burada SQL veritabanına LOG atan bir kod olduğunu varsayalım...
 // ...
 // ...
 // ...
end;

{ TLogcu_MAIL }

procedure TLogcu_MAIL.Log(const aLog: String);
begin
 ShowMessage('Mail ile loglama yapıldı: ' + aLog);
 // Burada EPOSTA ile LOG gönderen bir kod olduğunu varsayalım...
 // ...
 // ...
 // ...
end;

{ TLogFabrikasi_SQL }

function TLogFabrikasi_SQL.CreateLogcu: ILogcu;
begin
 // Factory Method tasarım deseninin tanımına göre log tutan bir nesne üretip dışarı gönderdik...
 Result := TLogcu_SQL.Create;
end;

{ TLogFabrikasi_SMS }

function TLogFabrikasi_SMS.CreateLogcu: ILogcu;
begin
 // Factory Method tasarım deseninin tanımına göre log tutan bir nesne üretip dışarı gönderdik...
 Result := TLogcu_SMS.Create;
end;

{ TLogFabrikasi_MAIL }

function TLogFabrikasi_MAIL.CreateLogcu: ILogcu;
begin
 // Factory Method tasarım deseninin tanımına göre log tutan bir nesne üretip dışarı gönderdik...
 Result := TLogcu_MAIL.Create;
end;

end.

Yukarıdaki örnekte de anlaşıldığı üzere bir Factory Method tanımının nasıl yapıldığına dair doyurucu bir örnek gördüğümüze göre artık bu yapıyı projelerimizde nasıl kullanacağımıza bakmalıyız. Bunun için bize bir kobay lazım. Burada Kobay'dan kasıt, sizin iş nesneleriniz olacak, kapsamı geniş olduğundan sadece kobay diye isimlendiriyorum fakat sizin için bu bir ORM nesnesi, bir dataset veya bir form bile olabilir... Alelade bir kobay nesnesi üreterek bu mekanizmanın nasıl çalıştığını daha iyi anlayabiliriz.

Ama ondan önce, yani daha iyisini önermeden önce ben de dahil zamanında birçoğumuzun sıklıkla düştüğü bir yanılgıya, kötü bir kodlamaya örnek vermek gerekiyor. Bu örnek önemli, çünkü konunun kıymetini arttırıyor. KirliKobay adıyla isimlendirdiğim nesneye daha yakından bakalım;

interface

type
 TKirliKobay = class                    //  Sıradan bir sınıf tanımı
   private
     Logger: TLogcu_SQL;                //  Böyle bir tip belirtimi sizi bu nesneye (TLogcu_SQL'e) bağımlı yapar. İşte bunu yapmayın!
   public
     constructor Create;                //  Klasik, herhangi bir nesneyi üretirken kulllandığımız sıradan bir CONSTRUCTOR metodu
     destructor Destroy; override;      //  Klasik yok edici metodumuz...
     procedure Kaydet;                  //  Loglamayı tetikleyeceğimiz nokta...
 end;

implementation

uses
 System.SysUtils;   // FreeAndNil

constructor TKirliKobay.Create;
begin
 inherited Create;                      //  
  Logger := TLogcu_SQL.Create;           //  Doğrudan TLoguc_SQL sınıfını ürettik ama bu modelde bu aslında yanlış bir davranış...
end;

destructor TKirliKobay.Destroy;
begin
 freeandnil(Logger);                    //  Doğal olarak, arkamızı temizlemek durumunda da kalıyoruz...
  inherited Destroy;                     //  
end;

procedure TKirliKobay.Kaydet;
begin
 ShowMessage('TKirliKobay bir şeyleri kaydetti');
  Logger.Log('Kirli bir loglama yaptık dolayısıyla TLogcu_SQL''e artık mahkumuz');
end;

TKirliKobay nesnesindeki Logger değişkenini doğrudan TLogcu_SQL nesnesine bağladık. İşte problem olan, yanlış olan nokta aslında burası. Çünkü bu nokta sizin hem kodunuzun esnekliğini bozuyor hem de o nesneye bir bağımlılık yaratıyor. Halbuki siz istediğiniz log nesnesiyle çalışabilmeli bununla birlikte ana kodunuz da bu değişiklikten "hiç bir şekilde" etkilenmemeli... Yukarıdaki KirliKobay nesnesi yine çalışır, yine bir şeyleri kaydeder ve SQL'e loglar atmaya yine devam eder, yani yine iş görür ama SQL dışında başka bir loglama tekniği kullanmak isterseniz o zaman sizin başınızı ağrıtır.

Eğer daha esnek bir yapı, nesnelerden daha bağımsız bir düzen kurmak istiyor ve ileriye dönük bir yatırım yapmak niyetindeysek bunun doğrusu aşağıdaki gibi bir yapı ile sağlanmalı;

unit Kobay_Objects_;

interface

uses
   Vcl.Dialogs                 //  ShowMessage
 , FactoryPattern_Objects      //  ILogcu, ILogFabrikasi
 ;

type
 ELogTipi = (ltSQL, ltSMS, ltMAIL);                                  //  Bu Enumerated Type, bizim bir nesnemizde hangi log ile çalışacağımızı seçmemize yardım edecek, elzem değil, tamamen bir tercih meselesidir...
 TKobay = class                                                      //  Bu bizim kurgusal bir nesnemiz, bunu siz bir TForm, bir TUniConnection gibi bir şey olarak da düşünebilirsiniz
   private
     Logger        : ILogcu;                                         //  Log tutacağımız nesnenin veri tipinin bir INTERFACE'yi kullandığına dikkat edin !!!
     LoggerFactory : ILogFabrikasi;                                  //  Log tutma nesnesini üreteceğimiz nesnenin veri tipinin bir INTERFACE'ye işaret ettiğine dikkat edin !!!
     FLogTipi      : ELogTipi;
     procedure SetLogTipi(const Value: ELogTipi);
   public
     constructor Create;                                             //  Klasik, herhangi bir nesneyi üretirken kulllandığımız sıradan bir CONSTRUCTOR metodu
     procedure Kaydet;                                               //  LOGLAMAYI TETİKLEYECEĞİMİZ METOD.
     property LogTipi: ELogTipi read FLogTipi write SetLogTipi;      //  Logcumuzu bununla belirleyeceğiz...
 end;

implementation

{ TBirNesne }

constructor TKobay.Create;       // Kurgusal nesnemizi üreteceğimiz CONSTRUCTOR metod.
begin
 inherited Create;              // Kurgusal nesnemizi üretiyoruz.
 LogTipi := ltSQL;              // Bir başlangıç değeri olarak SQL ile loglama yapacağımızı belirtmiş olduk.
end;

procedure TKobay.SetLogTipi(const Value: ELogTipi);
begin
  FLogTipi := Value;

 // Bu noktada biz yine soyut bir arabirim vasıtasıyla Logcu üreten bir fabrikadan faydalanmak istediğimizi belirtiyoruz
  // Seçtiğimiz tipe göre fabrika arabirimimiz bize bir LOG FABRİKASI üretiyor
  case  Value   of
        ltSMS : LoggerFactory := TLogFabrikasi_SMS.Create;
        ltSQL : LoggerFactory := TLogFabrikasi_SQL.Create;
        ltMAIL: LoggerFactory := TLogFabrikasi_MAIL.Create;
  end;

 // Bu noktada hangi fabrikayı kullandığımızın artık bizim için bir anlamı yok, çünkü hangi fabrika olursa olsun, biz bize bir log tutan nesne geleceğini artık biliyoruz.
 Logger := LoggerFactory.CreateLogcu; // Yukarıdaki tercihimiz ne olursa olsun artık, fabrikamız bize bir LOGCU nesnesi üretiyor
end;

procedure TKobay.Kaydet;
begin
 // Bu metod, bizim kobay nesnemizin birşeyleri kaydettiği nokta.
 // Temsili olarak verinin bir yerlere kaydedildiğini varsayalım...
 ShowMessage('Veri Kaydedildi');

 // Burası ise LOG tuttuğumuz nokta, şimdi size bir soru LOGGER hangi nesneyi kullanıyor? LOGGER'in tipi ne sizce?
  Logger.Log('TBirNesne.Kaydet');   // Logger'in tipinin ne olduğunun artık bu noktadan sonra bir önemi yok çünkü siz bunu zaten yukarıda belirttiniz, sizin için artık bu noktadan sonra log düzgün tutulmuş mu tutulmamış mı ona bakmanız gerekir...
end;

end.

Kobayımızı da tanımladığımıza göre artık projemizde bunu nasıl kullanabilirve test edebiliriz basit bir örnekle görelim;

unit Ana_;

interface

uses
 Kobay_Objects_, // TKobay  ( BU ARADA LOGCU VE LOGFABRIKASI ile ilgili herhangi bir uniti çağırmadık dikkat ettiyseniz... )

 Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
 TAna = class(TForm)
   BT_Save: TButton;
   procedure FormCreate(Sender: TObject);
   procedure FormDestroy(Sender: TObject);
   procedure BT_SaveClick(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
   NesneninTeki: TKobay;
 end;

var
 Ana: TAna;

implementation

{$R *.dfm}

procedure TAna.FormCreate(Sender: TObject);
begin
 // Formumuzun OnCreate olayına kobay nesnemizi üreten bir kod ekliyoruz
 NesneninTeki := TKobay.Create;
end;

procedure TAna.FormDestroy(Sender: TObject);
begin
 // Formumuz yok edilmeden hemen önce kobay nesnemizi yok ediyoruz...
 FreeAndNil(NesneninTeki);
end;

procedure TAna.BT_SaveClick(Sender: TObject);
begin
 //  SAVE adlı butona bastığımızda kobay nesnenin loglama tipini her seferinde değiştiren bir yapı kurduk
 //  Bu sadece yapının dinamikliğini sergilemek amacıyla böyle yapıldı, butona her bastığınızda loglama metodu değişecek...
 case NesneninTeki.LogTipi of
      ltSMS : NesneninTeki.LogTipi := ltSQL;
      ltSQL : NesneninTeki.LogTipi := ltMAIL;
      ltMAIL: NesneninTeki.LogTipi := ltSMS;
 end;

 // kobay nesnemiz bir şeyleri kaydedip hemen kendi içinde bir de log tutuyor fakat bu işler arka tarafta yapılmış oluyor...
  NesneninTeki.Kaydet;
end;

end.

Gördüğünüz gibi başlarda çok karmaşıkmış gibi gelse de aslında gayet basit ve gayette temiz bir yapı. Projenizdeki kodu yönetebilmenize ve onu daha esnek hale getirebilmenize çok fayda sağlıyor. İşin başında belki biraz yorulabilirsiniz ama terlediğinize değecektir...

Bu arada fark ettiniz mi bilmiyorum ama kobay nesnemiz haricinde hiç bir yerde free ve destroy gibi dispose edici, yokedici metodları çağırmadık. Sizce bir yerlerde memory leak oluşmuş mudur? ( Bunu bir ev ödevi olarak kabul edin ve sebeplerini birazcık araştırın, interface'ler altında yatan harika bir mekanizmanın olduğunu fark edeceksiniz Smile )

Umarım faydalı olmuştur, başka bir yazıda görüşmek üzere...

Bu konuyu yazdır