Arayüzleri Uygulama
Coddy'nin C Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 41 / 61.
Artık bir interface'in ne olduğunu —yalnızca function pointers içeren bir struct— anladığınıza göre, bu sözleşmeyi yerine getiren concrete implementations oluşturmanın zamanı geldi.
Önceki dersteki ILogger arayüzünü hatırlayalım:
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;Bu arayüzü uygulamak için, LogFunc imzasıyla eşleşen gerçek fonksiyonlar yazarız, ardından bu fonksiyonların atandığı ILogger örnekleri oluştururuz:
void console_log(const char* message) {
printf("[CONSOLE] %s\n", message);
}
void file_log(const char* message) {
printf("[FILE] %s\n", message); // Dosya çıktısı simüle ediliyor
}
ILogger create_console_logger() {
ILogger logger = { console_log };
return logger;
}
ILogger create_file_logger() {
ILogger logger = { file_log };
return logger;
}Her bir "constructor" fonksiyonu, içine farklı bir fonksiyon bağlanmış bir ILogger döndürür. Bu logger'ları kullanan kodun, hangi uygulamayı (implementation) aldığını bilmesine gerek yoktur:
void do_work(ILogger* logger) {
logger->log("Starting work...");
logger->log("Work complete!");
}
int main() {
ILogger console = create_console_logger();
ILogger file = create_file_logger();
do_work(&console); // console_log kullanır
do_work(&file); // file_log kullanır
return 0;
}do_work fonksiyonu, günlükleme uygulamasından tamamen ayrılmıştır. Çekirdek mantığın hiçbirini değiştirmeden günlükleyicileri serbestçe değiştirebilirsiniz — bir arayüze göre programlamanın gücü budur.
Görev
KolayFarklı uygulamaların aynı arayüz sözleşmesini nasıl yerine getirebileceğini gösteren bir INotifier sistemi kuralım. Her ikisi de ortak bir arayüze uyan ancak farklı çıktılar üreten somut bildirimciler — bir EmailNotifier ve bir SMSNotifier — oluşturacaksınız.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
notifier.h: Arayüzü burada tanımlayın. Birconst char*mesajı alan ve hiçbir şey döndürmeyenNotifyFuncadında bir fonksiyon göstericisi (function pointer) türü oluşturun. Ardından, yalnızca bu türde birnotifyfonksiyon göstericisi içeren birINotifierstruct'ı tanımlayın. Ayrıca, her biri değer olarak birINotifierdöndüren iki yapıcı (constructor) fonksiyon bildirin:create_email_notifiervecreate_sms_notifier.notifier.c: Somut bildirim fonksiyonlarını ve yapıcıları burada uygulayın. Şunları oluşturun:email_notify— mesajı şu formatta yazdırır:[EMAIL] messagesms_notify— mesajı şu formatta yazdırır:[SMS] messagecreate_email_notifier—email_notifyfonksiyonuna bağlanmış birINotifierdöndürürcreate_sms_notifier—sms_notifyfonksiyonuna bağlanmış birINotifierdöndürür
main.c: Her şeyi burada birleştirin. Bir bildirim türü ve bir mesaj okuyun, yapıcı fonksiyonları kullanarak uygun bildirimciyi oluşturun ve bildirimi arayüz üzerinden gönderin.
Programınız iki girdi alacaktır: bir bildirim türü (e-posta için 1, SMS için 2) ve gönderilecek bir mesaj.
Uygun bildirimciyi oluşturmak için yapıcı fonksiyonları kullanın, ardından mesajı görüntülemek için arayüz üzerinden notify fonksiyonunu çağırın.
Tür 1 ve mesaj Meeting at 3pm olduğunda örnek çıktı:
[EMAIL] Meeting at 3pmTür 2 ve mesaj Your code shipped olduğunda örnek çıktı:
[SMS] Your code shippedBu desenin gücü, main.c dosyasının her bir bildirimcinin dahili olarak nasıl çalıştığını bilmesine gerek duymamasıdır — sadece arayüzün notify fonksiyonunu çağırır ve doğru uygulama yürütülür. Başlık dosyanızda include guard kullanmayı unutmayın.
Kopya kağıdı
C'de bir arayüz (interface) uygulamak için, fonksiyon göstericisi imzasıyla eşleşen somut fonksiyonlar oluşturun ve ardından bunları arayüz örneklerine atayın.
Arayüzü fonksiyon göstericileri ile tanımlayın:
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;Somut uygulamaları oluşturun:
void console_log(const char* message) {
printf("[CONSOLE] %s\n", message);
}
void file_log(const char* message) {
printf("[FILE] %s\n", message);
}Arayüz örnekleri oluşturmak için yapıcı (constructor) fonksiyonlar kullanın:
ILogger create_console_logger() {
ILogger logger = { console_log };
return logger;
}
ILogger create_file_logger() {
ILogger logger = { file_log };
return logger;
}Arayüzü kullanan kod, belirli uygulamalardan bağımsızdır (decoupled):
void do_work(ILogger* logger) {
logger->log("Starting work...");
}
int main() {
ILogger console = create_console_logger();
ILogger file = create_file_logger();
do_work(&console); // console_log kullanır
do_work(&file); // file_log kullanır
return 0;
}Kendin dene
#include <stdio.h>
#include "notifier.h"
int main() {
int type;
char message[256];
// Bildirim türünü oku (e-posta için 1, SMS için 2)
scanf("%d", &type);
getchar(); // yeni satır karakterini tüket
// Mesajı oku
fgets(message, sizeof(message), stdin);
// Varsa sondaki yeni satır karakterini kaldır
int len = 0;
while (message[len] != '\0') len++;
if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
// TODO: Türe göre uygun bildirimciyi oluştur
// Tip 1 için create_email_notifier() kullanın
// Tip 2 için create_sms_notifier() kullanın
// TODO: Arayüz üzerinden bildirim fonksiyonunu çağırın
// notifier.notify(message);
return 0;
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Object Oriented Programming bölümündeki tüm dersler
1Modüler Programlama Temelleri
Başlık DosyalarıInclude Guard'larKaynak DosyalarıStatik FonksiyonlarÖzet: Modüler Hesap Makinesi4Kapsülleme
Opaque Pointer KavramıOpaque Struct TanımlamaGetter ve Setter MetotlarıSetter Metotlarında DoğrulamaÖzet: Gizli Kutu2Nesneler ve Metotlar
Nesne Olarak Struct'lar'Self' İşaretçisiConst Doğruluğuİşaretçi vs DeğerYardımcı MetotlarÖzet: Point Manager5Proje: Basit Banka Hesabı
Proje KurulumuHesabın Oluşturulması8Polimorfizm
Struct'larda Fonksiyon İşaretçileriMetotları Simüle EtmeArayüz KavramıArayüzleri UygulamaPolimorfik İterasyonÖzet: Greeter3Nesne Yaşam Döngüsü
Constructor DeseniDestructor DeseniStack İlklendirmeDerin KopyalamaÖzet: String Wrapper6Kompozisyon Yoluyla Kalıtım
Struct Gömmeİlk Üye KuralıÜst Üyelere ErişimUpcastingÖzet: Şekil Hiyerarşisi