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-RegisterLoggingDecorator
: loggt alle gesendeten DatenCRCDecorator
: 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;
}