Interface’ler ile bir senaryo..

// 15 Mayıs 2009 // Delphi, Programlama

Bu konu çok derin bir konu ancak kısaca bir giriş yapmak istiyorum. Aslında koddan çok kullanım amacını anlatmaya çalışacağım.O yüzden bir senaryo üreteceğim.Diyelim ki; siz component üreten bir firmada yazılım proje yöneticisisiniz. Her türlü tasarım sizden geçiyor ve diyelim ki veritabanı bağlantıları ile ilgili componentler geliştirmeniz gerekiyor.Ekibinizde yeterli sayıda programcınız var.Ancak programcıların çok başına buyruk marjinal insanlar olduklarını da deneyimlerinizle biliyorsunuz ve onlara da yeterince güvenmiyorsunuz ;) Mesela, daha somut örnekler verirsek. Diyelim ki, üretilecek olan componentler SQL Server’a, Sysbase’e , Oracle’a , Interbase’e , Informix’e , DB2′ya bağlanabilmeli diye bir zorunluluk var.Bunu sağlayabilmek adına ekibi topladınız ve programcılarınızın yetenekleri ölçüsünde her bir sınıfın tasarımını ilgili kişilere verdiniz.Ve biliyorsunuz ki herhangi bir veritabanına bağlanacak olan bir sınıfın temelde uygulaması gereken iki metod var Open ve Close ve siz de programcılarınıza bu tecrübenizi ve bilginizi aktardınız. Ama dedik ya programcılar marjinal insanlardır diye. Bakın programcılarımız ne yaptı:

TSQLConnection = class(TBaseConnection)
public
  procedure OpenConnection;
  procedure CloseConnection;
end;

TOracleConnection = class(TBaseConnection)
public
  procedure Open;
  procedure Close;
end;

TSybaseConnection = class(TBaseConnection)
public
  procedure Connect;
  procedure Disconnect;
end;


Şimdi yukarıdaki tasarımda mantıksız adlandırma kuralları yok gibi görünüyor.Ama siz biliyorsunuz ki bu şekilde olmamalı.O kadar da söylediniz “standartlara uyun arkadaşlar, metodlar Open ve Close isimlerinden başka bir şey olmayacak!” diye ama baktınız ki böyle yazmışlar. Olur olur canım, hemen olmaz demeyin. Eee ne olacak şimdi, programcıları işten mi atacaksınız..Saç baş mı yolacaksınız.? Çözümün nasıl stabil bir şekilde oluşturulabileceğine geçmeden önce neden bu tasarımın sıkıntılar doğurabileceğinden biraz bahsetmek gerek sanırım. Diyelim ki ben sizin yazdığınız sınıfları satın alan bir programcıyım.Ve polimorphism kullanmak istiyorum.Şöyleki :

var
   bConnection : TBaseConnection;
 begin
   case radioGroup.ItemIndex of
     0 : bConnection := TSQLConnection.Create(nil);
     1 : bConnection := TOracleConnection.Create(nil);
     2 : bConnection := TSybaseConnection.Create(nil);
   end;
 end;

Yukarıdaki kodda şu ana kadar bir sorun yok.Biz TRadioGroup vasıtası ile kullanıcının yaptığı seçim nezdinde ilgili veritabanına bağlanmak için çok biçimlilikten (polymorphism) faydalanmak üzere yapıyı oluşturuyoruz.Herşeyde güzel gidiyor.Neyse devam edelim bakalım ne olacak..

var
   bConnection : TBaseConnection;
 begin
   case radioGroup.ItemIndex of
     0 : bConnection := TSQLConnection.Create(nil);
     1 : bConnection := TOracleConnection.Create(nil);
     2 : bConnection := TSybaseConnection.Create(nil);
   end;
   {
    Şimdi biz burada OpenConnection mu Open mı Connect mi hangisini çağıracağız ?
    bConnection.OpenConnection;
    bConnection.Open;
    bConnection.Connect;
   }
end;

İşte sorun başladı. Programcı bir baktı, TSQLConnection sınıfı bağlantı için OpenConnection metodunu kullanmanızı isterken, TOracleConnection bağlantı için Open metodunu, TSybaseConnection sınıfı da Connect’i kullanmanızı istiyor.. Oooo dediniz şimdi olmadı, componentleri satın aldığınız firmayı en iyi ihtimalle sadece küfür ettiniz ve yazılımınızı polymorhism’in desteğinden yoksun bir şekilde geliştirmeye devam ettiniz.Ama her fırsat ve ortamda da bu component setini almaması için tüm arkadaşlarınıza önerilerde bulundunuz.

Şimdi gelelim bunun çözümüne.İşi daha başından sıkı tutmak gerekiyor. Benim bu tarz sorunları engellemek adına sizlerle paylaşabileceğim önerim interface’lerin kullanılmasıdır.Peki bu nasıl olacak,gösterelim:

IBaseConnection = Interface
  [‘{4D3EAB7E-F7A5-4897-9F0B-6943F4745581}’]
    procedure Open;
    procedure Close;
  end;

  TSQLConnection = class(TBaseConnection, IBaseConnection)
  public
    procedure Open;
    procedure Close;
  end;

  TOracleConnection = class(TBaseConnection, IBaseConnection)
  public
    procedure Open;
    procedure Close;
  end;

  TSybaseConnection = class(TBaseConnection, IBaseConnection)
  public
    procedure Open;
    procedure Close;
  end;

Yukarıdaki yapıda IBaseConnection adlı bir arabirim (Interface) var ve bu interface’in Open ve Close adlı iki metodu var.Dikkat edilirse, tüm bağlantı sınıfları aynı interface’i uygulayacaklarını taahhüt etmiş durumdalar.

TSQLConnection = class(TBaseConnection, IBaseConnection)
TOracleConnection = class(TBaseConnection, IBaseConnection)
TSybaseConnection = class(TBaseConnection, IBaseConnection)

yazarak bu taahhütte bulunmuş oluyorlar. Bu tanımlamalar ilgili sınıfların IBaseConnection interface’inden dolayı Open ve Close metodlarını sınıf içerisinde tanımla zorunluluğunu getirmiş oluyor.Böylelikle tüm bağlantı sınıflarının Open ve Close isimli birer metodu olması gerektiğini garanti altına almış oluyorsunuz.Sınıflarınızı bu kuralla oluşturduğunuzda sizin componentlerinizi satın alan programcının yeni koduna hep birlikte bakalım isterseniz:

var
   bConnection : TBaseConnection;
 begin
   case radioGroup.ItemIndex of
     0 : bConnection := TSQLConnection.Create(nil);
     1 : bConnection := TOracleConnection.Create(nil);
     2 : bConnection := TSybaseConnection.Create(nil);
   end;
   bConnection.Open;
end;

Şimdi programcı da memnun sizde memnunsunuz.(Çünkü size küfür eden kimse yok, kulaklarınız da uğuldamıyor).

Haa tüm bu interface şartınıza rağmen programcınız o interface’i kullanmamışsa o zaman onu gönül rahatlığı ile işten atabilir hatta bir ton sopa bile atabilirsiniz.. :)

Saygılar, sevgiler..

“Interface’ler ile bir senaryo..” için 1 Yorum

  1. geyikben diyor ki:

    :) çok başıma geliyor çook. Gerçi işi bilen adam bulmakta çok zor

Yorum Yazın