Wie sieht eine saubere Schnittstelle aus, damit verschiedene Dekoratoren kombinierbar bleiben?

Alle Komponenten sollten ein gemeinsames Interface implementieren, das einfache Operationen wie send(), receive() etc. bereitstellt. Jeder Decorator sollte nur dort eingreifen, wo er Funktionalität hinzufügen will, und den Rest delegieren.

Ziel:

Ein DataStream-Interface mit verschiedenen Dekoratoren:

  • BaseStream: schreibt Daten in ein Dummy-Register
  • LoggingDecorator: loggt alle gesendeten Daten
  • CRCDecorator: fügt am Ende der Nachricht eine einfache CRC-Prüfsumme hinzu

Alle Klassen implementieren die gleiche Schnittstelle, wodurch sie beliebig kombinierbar bleiben.

#include <iostream>
#include <cstdint>
#include <cstring>

class IDataStream {
public:
virtual void send(const uint8_t* data, size_t len) = 0;
virtual ~IDataStream() = default;
};

// --- Basiskomponente: Simulierte Ausgabe ---
class BaseStream : public IDataStream {
public:
void send(const uint8_t* data, size_t len) override {
std::cout << "[BaseStream] Sending: ";
for (size_t i = 0; i < len; ++i) {
std::cout << std::hex << (int)data[i] << " ";
}
std::cout << std::dec << "\n";
}
};

// --- Decorator-Basis-Klasse ---
class StreamDecorator : public IDataStream {
protected:
IDataStream& wrapped;

public:
StreamDecorator(IDataStream& stream) : wrapped(stream) {}
};

// --- Logging-Dekorator ---
class LoggingDecorator : public StreamDecorator {
public:
LoggingDecorator(IDataStream& stream) : StreamDecorator(stream) {}

void send(const uint8_t* data, size_t len) override {
    std::cout << "[LoggingDecorator] Logging " << len << " bytes\n";
    wrapped.send(data, len);
}

};

// --- CRC-Dekorator ---
class CRCDecorator : public StreamDecorator {
public:
CRCDecorator(IDataStream& stream) : StreamDecorator(stream) {}

void send(const uint8_t* data, size_t len) override {
    uint8_t buffer[256];
    if (len + 1 > sizeof(buffer)) return; // Sicherheitscheck

    memcpy(buffer, data, len);
    buffer[len] = calculateCRC(data, len);
    std::cout << "[CRCDecorator] Appending CRC\n";
    wrapped.send(buffer, len + 1);
}

private:
uint8_t calculateCRC(const uint8_t* data, size_t len) {
uint8_t crc = 0;
for (size_t i = 0; i < len; ++i) {
crc ^= data[i];
}
return crc;
}
};

Verwendung

int main() {
BaseStream base;
LoggingDecorator logger(base);
CRCDecorator crc(logger); // Reihenfolge: CRC außen, Logging innen

uint8_t msg[] = { 0xAA, 0xBB, 0xCC };
crc.send(msg, sizeof(msg));

return 0;

}
com

Newsletter Anmeldung

Bleiben Sie informiert! Wir informieren Sie über alle neuen Beiträge (max. 1 Mail pro Woche – versprochen)