Menu
Coddy logo textTech

C++'ta Arayüz Tasarımı

Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 61 / 104.

C++'ta bir interface, (virtual) destructor hariç her üye fonksiyonun pure virtual olduğu bir abstract class'tır. Bazı uygulamalar içerebilen abstract class'ların aksine, interface'ler yalnızca hangi işlemlerin var olması gerektiğini tanımlar — herhangi bir davranış olmaksızın bir sözleşme belirtirler.

class Drawable {
public:
    virtual void draw() = 0;
    virtual void resize(double factor) = 0;
    virtual ~Drawable() = default;
};

Bu Drawable arayüzü, uygulayan herhangi bir sınıfın draw() ve resize() metotlarına sahip olacağını garanti eder, ancak bunların nasıl çalıştığı hakkında hiçbir şey söylemez. Bu ayrım güçlüdür - kod, somut türler hakkında hiçbir şey bilmeden arayüze bağlı olabilir.

class Circle : public Drawable {
    double radius;
public:
    Circle(double r) : radius(r) {}
    void draw() override { std::cout << "Drawing circle" << std::endl; }
    void resize(double factor) override { radius *= factor; }
};

class Button : public Drawable {
    std::string label;
public:
    Button(std::string l) : label(l) {}
    void draw() override { std::cout << "Drawing button: " << label << std::endl; }
    void resize(double factor) override { /* butonu yeniden boyutlandır */ }
};

Bir sınıf birden fazla arayüz uygulayabilir; bu da nesnelerin farklı rolleri üstlenebildiği esnek tasarımlara olanak tanır:

class Clickable {
public:
    virtual void onClick() = 0;
    virtual ~Clickable() = default;
};

class IconButton : public Drawable, public Clickable {
public:
    void draw() override { std::cout << "Drawing icon" << std::endl; }
    void resize(double factor) override { }
    void onClick() override { std::cout << "Clicked!" << std::endl; }
};

Arayüzler gevşek bağlılığı (loose coupling) teşvik eder - kodunuz somut uygulamalar yerine soyutlamalara dayanır, bu da genişletmeyi ve test etmeyi kolaylaştırır.

challenge icon

Görev

Kolay

Arayüzlerin farklı cihaz türleri için sözleşmeleri nasıl tanımladığını gösteren bir cihaz yönetim sistemi kuralım. Cihazların uygulayabileceği iki ayrı arayüz oluşturacak, ardından bu sözleşmelerden birini veya her ikisini yerine getiren somut cihaz sınıfları inşa edeceksiniz.

Kodunuzu üç dosya halinde düzenleyeceksiniz:

  • Interfaces.h: Farklı cihaz yeteneklerini temsil eden iki saf soyut sınıf (arayüz) tanımlayın:

    Powerable — açılıp kapatılabilen herhangi bir cihaz:

    • Saf sanal bir powerOn() metodu
    • Saf sanal bir powerOff() metodu
    • std::string döndüren saf sanal bir getPowerStatus() metodu
    • Sanal bir yıkıcı (destructor)

    Connectable — bir ağa bağlanabilen herhangi bir cihaz:

    • Saf sanal bir connect(const std::string& network) metodu
    • Saf sanal bir disconnect() metodu
    • std::string döndüren saf sanal bir getConnectionInfo() metodu
    • Sanal bir yıkıcı (destructor)
  • Devices.h: Bu arayüzleri kullanan somut cihaz sınıflarını uygulayın:

    Lamp — sadece Powerable arayüzünü uygular:

    • Özel (private) bir bool isOn üyesi (false olarak başlar)
    • Özel (private) bir std::string name üyesi
    • Lambanın adını alan bir kurucu (constructor)
    • powerOn(), isOn değerini true yapar ve şunu yazdırır: <name>: Light turned on
    • powerOff(), isOn değerini false yapar ve şunu yazdırır: <name>: Light turned off
    • getPowerStatus(), duruma göre "ON" veya "OFF" döndürür

    SmartTV — hem Powerable hem de Connectable arayüzlerini uygular:

    • Özel (private) üyeler: bool isOn (false olarak başlar), std::string brand, std::string currentNetwork (boş olarak başlar)
    • TV'nin markasını alan bir kurucu (constructor)
    • powerOn(), isOn değerini true yapar ve şunu yazdırır: <brand> TV: Powered on
    • powerOff(), isOn değerini false yapar, ağı temizler ve şunu yazdırır: <brand> TV: Powered off
    • getPowerStatus(), "ON" veya "OFF" döndürür
    • connect(), ağ adını saklar ve şunu yazdırır: <brand> TV: Connected to <network>
    • disconnect(), ağı temizler ve şunu yazdırır: <brand> TV: Disconnected
    • getConnectionInfo(), bağlıysa "Connected to <network>", boşsa "Not connected" döndürür
  • main.cpp: Üç girdi okuyun (her biri ayrı bir satırda):
    1. Lamba adı
    2. TV markası
    3. Ağ adı

    Bir Lamp ve bir SmartTV oluşturun. Aynı arayüzün farklı cihazlarla nasıl kullanılabileceğini gösterin:

    İlk olarak, her iki cihazla da Powerable arayüzü üzerinden çalışın. Her ikisinin işaretçilerini (pointer) bir Powerable* dizisinde saklayın, ardından döngü ile her biri için powerOn() metodunu çağırın ve durumlarını şu şekilde yazdırın: Status: <powerStatus>

    Boş bir satır yazdırın, ardından SmartTV ile Connectable arayüzü üzerinden çalışın. SmartTV'niz için bir Connectable* işaretçisi oluşturun, ağ adı ile connect() metodunu çağırın ve şunu yazdırın: Connection: <connectionInfo>

    Başka bir boş satır yazdırın, ardından Powerable dizisi üzerinden her iki cihazı da kapatın ve son durumlarını gösterin.

Örneğin, Desk Lamp, Samsung ve HomeWiFi girdileriyle:

Desk Lamp: Light turned on
Status: ON
Samsung TV: Powered on
Status: ON

Samsung TV: Connected to HomeWiFi
Connection: Connected to HomeWiFi

Desk Lamp: Light turned off
Status: OFF
Samsung TV: Powered off
Status: OFF

SmartTV'nin hangi arayüz işaretçisini kullandığınıza bağlı olarak nasıl hem Powerable hem de Connectable olarak ele alınabildiğine dikkat edin. Bu esneklik, birden fazla arayüz uygulamanın gücüdür; kodunuz, somut türü bilmesine gerek kalmadan, ihtiyaç duyduğu sözleşmeyi yerine getiren herhangi bir cihazla çalışabilir.

Kendin dene

#include <iostream>
#include <string>
#include "Devices.h"

using namespace std;

int main() {
    // Girdileri oku
    string lampName;
    string tvBrand;
    string networkName;
    
    getline(cin, lampName);
    getline(cin, tvBrand);
    getline(cin, networkName);
    
    // TODO: Bir Lamp ve bir SmartTV nesnesi oluşturun
    
    // TODO: Her iki cihazı da içeren bir Powerable* işaretçi dizisi oluşturun
    
    // TODO: Dizi üzerinde döngü kurun ve her cihazda powerOn() fonksiyonunu çağırın
    // Her powerOn() işleminden sonra şunu yazdırın: Status: <powerStatus>
    
    // TODO: Boş bir satır yazdırın
    
    // TODO: SmartTV için bir Connectable* işaretçisi oluşturun
    // Ağ adı ile connect() fonksiyonunu çağırın
    // Şunu yazdırın: Connection: <connectionInfo>
    
    // TODO: Boş bir satır yazdırın
    
    // TODO: Powerable dizisi üzerinde döngü kurun ve her cihazda powerOff() fonksiyonunu çağırın
    // Her powerOff() işleminden sonra şunu yazdırın: Status: <powerStatus>
    
    return 0;
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler