Arayüzler, sınıflara rehberlik etmek üzere oluşturulan nesneye dayalı programlamanın en önemli özelliklerinden biridir. Sınıfların hangi metotları ve özellikleri içermesi gerektiğini arayüzler içerisinde bildiriyoruz.
Arayüz Oluşturma
interface IKisi { string adSoyad { get; set; } string adres { get; set; } string departman { get; set; } void bilgi(); }
Arayüzler “interface” anahtar sözcüğü ile oluşturulur. Zorunlu olmamakla birlikte arayüz isimleri genellikle “I” harfiyle başlatılır. Böylece “I” ön ekini gören bir programcı onun bir arayüz olduğunu anlar. Arayüz içerisinde özelliklerin ve metotların sadece bildirimi yapılır. Yani herhangi bir şekilde özelliklere bir değer atanmaz sadece türleri ve isimleri yazılır, aynı şekilde metotların içerisine kodlar yazılmaz sadece geri dönüş türleri ve isimleri yazılır.
Arayüzlerin Sınıflara İmplement Edilmesi
class Yonetici : IKisi { public string adSoyad { get; set; } public string adres { get; set; } public string departman { get; set; } public void bilgi() { Console.WriteLine(" {0} isimli çalışan {1} departmanında yöneticidir.",adSoyad,departman); } }
IKisi arayüzü, Yonetici sınıfına implement edildiği için (1.Satır) Yonetici sınıfı, IKisi arayüzünde bildirimi yapılmış olan özellikleri ve metotları içermek zorundadır. Yonetici sınıfı içerisine, IKisi arayüzünde bildirimi yapılmış metotlar ve özellikler haricinde Yonetici sınıfına has metotlar ve özellikler de tanımlanabilir.
Arayüzlere Neden İhtiyaç Duyarız?
Arayüzlerin geniş bir kullanım alanı bulunmaktadır. Basit bir örnek üzerinden anlatacak olursak;
interface IKisi { string adSoyad { get; set; } string adres { get; set; } string departman { get; set; } void bilgi(); } class Yonetici : IKisi { public string adSoyad { get; set; } public string adres { get; set; } public string departman { get; set; } public void bilgi() { Console.WriteLine(" {0} isimli çalışan {1} departmanında yöneticidir.",adSoyad,departman); } } class Isci : IKisi { public string adSoyad { get; set; } public string adres { get; set; } public string departman { get; set; } public void bilgi() { Console.WriteLine(" {0} isimli çalışan {1} departmanında işçidir.", adSoyad, departman); } }
Arayüz kullanımı sınıflarımızı bir standart çerçevesinde yapılandırmamızı sağlamaktadır. IKisi arayüzünün Isci ve Yonetici sınıflarına implement edildiğini gören bir programcı, bu sınıfların içerisinde adSoyad, adres, departman gibi özelliklerin olduğunu ve bu özelliklere erişilerek gerekli bilgilerin alınabileceğini bilecektir.
Örneğin, Yonetici ve Isci sınıflarından oluşturulan nesnelerin içerisindeki adSoyad özelliğini ekrana yazdıran bir metot yazalım. Arayüzlerin sağlamış olduğu kolaylıktan faydalanmıyor olsaydık bu işlemi aşağıdaki gibi yapıyor olurduk;
class Program { public void adSoyadBilgisi(Yonetici yonetici) { Console.WriteLine(yonetici.adSoyad); } public void adSoyadBilgisi(Isci isci) { Console.WriteLine(isci.adSoyad); } }
İki farklı metot tanımlamamız gerekirdi. Bu metotlardan biri Yonetici sınıfı türünden parametre alırken, diğeri Isci sınıfı türünden parametre alırdı. Ancak arayüzler sayesinde bu işlemi tek bir metot yazarak yapabiliriz.
class Program { public void adSoyadBilgisi(IKisi kisi) { Console.WriteLine(kisi.adSoyad); } }
IKisi arayüzü, Yonetici ve Isci sınıflarına implement edildiği için bu sınıflardan oluşturulan nesneler, IKisi arayüzü türündeki bir parametrede tutulabilir. Bu yüzden adSoyadBilgisi() metoduna parametre olarak Yonetici veya Isci sınıfından oluşturulan nesneleri gönderebiliriz. Bu parametre aracılığı ile ilgili nesnelerin sadece IKisi arayüzünden gelen özellik ve metotlarına erişebiliriz.
Çoklu İmplementasyon
Bir sınıfa birden fazla arayüz implement edilebilir. Örnek bir senaryo üzerinden konuyu anlatacak olursak; Bir fabrika için otomasyon programı yazdığımızı düşünelim. Fabrikada 3 farklı çalışan türü olsun, bunlar yönetici, işçi ve robot. Her bir çalışanın ID, ad-soyad, adres, maaş, departman ve toplam çalışma saati bilgisi olsun.
interface ICalisan { int id { get; set; } string adSoyad { get; set; } string adres { get; set; } double maas { get; set; } string departman { get; set; } ulong toplamCalismaSaati { get; set; } }
Eğer arayüz tasarımını yukarıdaki gibi yaparsak ICalisan arayüzünü, oluşturacağımız Yonetici ve Isci sınıflarına implement edebiliriz ancak Robot sınıfına implement edemeyiz. Çünkü robotların adlarının ve adreslerinin olmayacağını ve maaş almayacaklarını biliyoruz. Bu yüzden ICalisan arayüzünü uygun bir şekilde parçalamamız gerekiyor.
interface ICalisan { int id { get; set; } string departman { get; set; } ulong toplamCalismaSaati { get; set; } } interface IKisi { string adSoyad { get; set; } string adres { get; set; } double maas { get; set; } }
ICalisan ve IKisi şeklinde iki arayüz oluşturduk. Yöneticiler ve işçiler hem çalışan hemde birer kişi olduğundan, bu sınıflara hem ICalisan arayüzünü hem de IKisi arayüzünü imlement edeceğiz. Robot sınıfına ise sadece ICalisan arayüzünü implement edeceğiz.
class Yonetici : ICalisan, IKisi { public int id { get; set; } public string adSoyad { get; set; } public string adres { get; set; } public double maas { get; set; } public string departman { get; set; } public ulong toplamCalismaSaati { get; set; } } class Isci : ICalisan, IKisi { public int id { get; set; } public string adSoyad { get; set; } public string adres { get; set; } public double maas { get; set; } public string departman { get; set; } public ulong toplamCalismaSaati { get; set; } } class Robot : ICalisan { public int id { get; set; } public string departman { get; set; } public ulong toplamCalismaSaati { get; set; } }
Kurumsal Mimarilerde Arayüz Kullanımı
Daha önce kurumsal mimaride bir uygulama geliştirmediyseniz bu bölümü şimdilik atlayabilirsiniz.
Bu başlıkta olabildiğince yalın bir şekilde arayüzlerin kurumsal mimarilerde ki kullanımına bir örnek vermeye çalışacağım. Kod kalabalığını arttırmamak ve konuyu daha anlaşılır bir şekilde anlatmak için sınıfları karışıklığa yer vermeyecek şekilde isimlendirip, konumuzun dışında olan kod satırlarına/bloklarına (veritabanı sorguları) yer vermemeye çalışacağım.
Bir projede farklı veritabanı yönetim sistemleri kullanılabilir. Projelerimizi bizden fazla veritabanı yönetim sistemine destek verecek şekilde geliştirebilmek için arayüzlerden faydalanabiliriz.
public interface IRepository { void insert(); void update(); void delete(); void save(); }
Öncelikle IRepository adını verdiğimiz arayüzün içerisinde, veritabanı üzerinde ekleme, silme, güncelleme, kaydetme gibi temel işlemleri yapacak metotların bildirimini yapıyoruz. Sonra bu arayüzü, farklı veritabanı yönetim sistemleri üzerinde işlem yapacak olan sınıflara implement ediyoruz.
public class MsSQLDB : IRepository { public void delete() { // MsSQL veritabanında silme işlemini gerçekleştirecek kodlar. Console.WriteLine("MsSQL -> delete() metodu çalıştı."); } public void insert() { // MsSQL veritabanına ekleme işlemini gerçekleştirecek kodlar. Console.WriteLine("MsSQL -> insert() metodu çalıştı."); } public void save() { // MsSQL veritabanına kaydetme işlemini gerçekleştirecek kodlar. Console.WriteLine("MsSQL -> save() metodu çalıştı."); } public void update() { // MsSQL veritabanında güncelleme işlemini gerçekleştirecek kodlar. Console.WriteLine("MsSQL -> update() metodu çalıştı."); } } public class OracleDB : IRepository { public void delete() { // Oracle veritabanında silme işlemini gerçekleştirecek kodlar. Console.WriteLine("Oracle -> delete() metodu çalıştı."); } public void insert() { // Oracle veritabanına ekleme işlemini gerçekleştirecek kodlar. Console.WriteLine("Oracle -> insert() metodu çalıştı."); } public void save() { // Oracle veritabanına kaydetme işlemini gerçekleştirecek kodlar. Console.WriteLine("Oracle -> save() metodu çalıştı."); } public void update() { // Oracle veritabanında güncelleme işlemini gerçekleştirecek kodlar. Console.WriteLine("Oracle -> update() metodu çalıştı."); } }
Projemizin hem Oracle veritabanına hemde MsSQL veritabanına destek vermesini istiyorsak; IRepository arayüzü içerisinde bildirimi yapılan metotları, OracleDB sınıfında Oracle vertabanında işlem yapacak şekilde, MsSQLDB sınıfında MsSQL veritabanında işlem yapacak şekilde yazmamız gerekiyor.
MsSQLDB ve OracleDB sınıfları ile artık hem MsSQL veritabanında hem de Oracle veritabanında işlem yapabiliyoruz.
public class ExampleManager : IRepository { private IRepository database; public ExampleManager(IRepository db) { database = db; } public void delete() { database.delete(); } public void insert() { database.insert(); } public void save() { database.save(); } public void update() { database.update(); } }
Son olarak ExampleManager isimli bir sınıf oluşturuyoruz, bu sınıftan nesne oluştururken yapıcı metoduna parametre olarak MsSQLDB sınıfından bir nesne gönderirsek ekleme, silme, güncelleme, kaydetme işlemini MsSQL veritabanı üzerinde yapacaktır, OracleDB sınıfından bir nesne gönderirsek de Oracle veritabanı üzerinde yapacaktır.
class Program { static void Main(string[] args) { ExampleManager example_1 = new ExampleManager(new MsSQLDB()); example_1.insert(); example_1.delete(); Console.WriteLine(new string('-', 40)); ExampleManager example_2 = new ExampleManager(new OracleDB()); example_2.insert(); example_2.delete(); } }
Ekran Çıktısı:
MsSQL -> insert() metodu çalıştı. MsSQL -> delete() metodu çalıştı. ---------------------------------------- Oracle -> insert() metodu çalıştı. Oracle -> delete() metodu çalıştı. Press any key to continue . . .
Serdar YILMAZ
Teşekkürler Serdar bey.
Serdar hocam, nice youtube olsun blog olsun değerli kişilerin bilgilerini paylaştım. Sizin kadar sade ve anlaşılır olanına rastlamadım. Bu konuyu da bu gün itibarı ile anlamış bulunmaktayım. Meğer anlaşılabilir bir konu imiş. Teşekkürler, tekrar teşekkürler.
Yazılarınızı çok değerli buluyorum.Devam etmeniz dileğiyle teşekkür ederim 🙂
Merhaba, olumlu geri bildiriminiz için teşekkürler.
Harika. Ellerine sağlık