#include <iostream>
#include <memory>
#include <string>

// Abstract interface: message sender (common abstraction for high-level and low-level modules)
class IMessageSender {
public:
    virtual ~IMessageSender() = default;
    virtual void sendMessage(const std::string& recipient,
                             const std::string& message) const = 0;
};

// Concrete implementation: email sender
class EmailSender : public IMessageSender {
public:
    void sendMessage(const std::string& recipient,
                     const std::string& message) const override {
        std::cout << "[Email] Sending to " << recipient
                  << ": " << message << std::endl;
    }
};

// Concrete implementation: SMS sender
class SmsSender : public IMessageSender {
public:
    void sendMessage(const std::string& recipient,
                     const std::string& message) const override {
        std::cout << "[SMS]   Sending to " << recipient
                  << ": " << message << std::endl;
    }
};

// High-level module: notification service — depends only on the IMessageSender abstraction
class NotificationService {
    std::unique_ptr<IMessageSender> sender_;
public:
    // Inject the concrete implementation through the constructor (dependency injection)
    explicit NotificationService(std::unique_ptr<IMessageSender> sender)
        : sender_(std::move(sender)) {}

    void notify(const std::string& recipient,
                const std::string& message) const {
        if (sender_) {
            sender_->sendMessage(recipient, message);
        }
    }
};

int main() {
    // Use EmailSender
    auto emailService = NotificationService(std::make_unique<EmailSender>());
    emailService.notify("user@example.com", "Hello via Email!");

    // Use SmsSender — no need to modify NotificationService code
    auto smsService = NotificationService(std::make_unique<SmsSender>());
    smsService.notify("+123456789", "Hello via SMS!");

    return 0;
}

results matching ""

    No results matching ""