Moderne Engineering-Systeme setzen auf ein breites Spektrum von Sensoren zur Überwachung von Temperatur, Druck, Feuchtigkeit, Vibration und Hunderten anderer Parameter. Jeder Sensortyp erzeugt Daten in seinem eigenen Format mit einzigartigen Protokollen, Kalibrierungsanforderungen und Kommunikationsmustern. Die Verwaltung dieser Heterogenität wird mit zunehmendem System und Integration neuer Sensortechnologien immer komplexer. Das Factory-Methodenmuster bietet eine bewährte architektonische Lösung für den Umgang mit verschiedenen Sensordaten mit Flexibilität, Skalierbarkeit und Wartbarkeit. In Kombination mit einem Headless-CMS wie Directus zum Speichern von Sensorkonfigurationen und Metadaten wird das Muster noch leistungsfähiger und ermöglicht eine dynamische Sensorregistrierung und Datenaufnahme ohne fest codierte Abhängigkeiten.

Das Factory Method Pattern verstehen

Die Factory-Methode ist ein Schöpfungs-Designmuster, das eine Schnittstelle zum Erstellen eines Objekts definiert, aber es den Unterklassen ermöglicht, zu entscheiden, welche Klasse instanziiert werden soll. Dieser Ansatz fördert die lose Kopplung, indem die Verantwortung für die Objekterstellung vom Client-Code auf dedizierte Fabrik-Unterklassen verlagert wird. In der Programmierung bedeutet dies, dass Sie Code schreiben können, der mit einem abstrakten Produkttyp arbeitet und sich auf Fabrikmethoden verlassen können, um konkrete Instanzen zur Laufzeit zu erzeugen.

Das Muster ist besonders wertvoll, wenn ein System mehrere Varianten eines Produkts unterstützen muss, ohne die Kernlogik zu verändern. Es folgt dem Open/Closed Principle : Ein System ist offen für Erweiterungen (neue Produkte), aber geschlossen für Modifikationen (bestehender Code bleibt unverändert). Für die Sensorverwaltung bedeutet dies die Möglichkeit, Unterstützung für neue Sensortypen hinzuzufügen, indem einfach eine neue Sensorklasse und die entsprechende Fabrik erstellt werden - keine Änderungen in der Sensorverarbeitungsmaschine oder der Datenpipeline.

Zu den wichtigsten Komponenten des Musters gehören:

  • Product – die abstrakte Schnittstelle, die alle konkreten Produkte implementieren müssen (z.B. .
  • ConcreteProduct – eine spezifische Implementierung der Produktschnittstelle (z. B. ).
  • Creator – eine abstrakte Klasse oder Schnittstelle, die die Factory-Methode deklariert, die ein Objekt zurückgibt.
  • ConcreteCreator – eine Unterklasse, die die Factory-Methode außer Kraft setzt, um eine bestimmte zu instanziieren.

Durch die Isolierung der Erstellungslogik vereinfacht das Factory Method-Muster auch das Testen und erleichtert die Abhängigkeitsinjektion.

Anwendung des Musters auf die Sensordatenverwaltung mit Directus

In einem typischen Engineering-IoT-System sind Sensoren über eine Einrichtung verteilt, wobei jede Datenmenge über ein Gateway oder Edge-Gerät gestreamt wird. Das Backend muss die Rohdaten interpretieren, Validierung anwenden und zur Analyse speichern. Eine gemeinsame Herausforderung besteht darin, dass jeder Sensortyp einen anderen Handler zum Analysieren seiner Ausgabe benötigt. Die Hardcodierung all dieser Handler in die Ingestion-Logik ist spröde und nicht wartungsfähig. Das Factory-Methode-Muster adressiert dies, indem die Erstellung von Sensorhandlern an Fabriken delegiert wird, die je nach Sensortyp oder Konfiguration ausgewählt werden können.

Um das System noch dynamischer zu gestalten, können wir Directus als zentrales Konfigurations-Repository verwenden. Directus ist ein Open-Source Headless CMS, das eine flexible Datenschicht mit REST- und GraphQL-APIs bereitstellt. Sensordefinitionen wie Typ, Kommunikationsprotokoll, Datenformat, Kalibrierkoeffizienten und sogar den Namen der entsprechenden Python- oder Java-Handlerklasse können in Directus-Sammlungen gespeichert werden. Wenn das System startet (oder wenn sich ein neuer Sensor registriert), liest es diese Konfigurationen und verwendet das Factory Method-Muster, um den entsprechenden Handler im laufenden Betrieb zu instanziieren.

Diese Kombination ergibt eine stark entkoppelte Architektur, bei der das Hinzufügen eines neuen Sensortyps reduziert wird auf:

  1. Erstellen einer neuen Handlerklasse, die die Standard-Sensorschnittstelle implementiert.
  2. Erstellen einer neuen Betonfabrik, die diesen Handler zurückgibt.
  3. Registrierung des Handler-Mappings in Directus (z. B. ein neuer Eintrag in einer "sensor types"-Sammlung).

Es muss sich kein vorhandener Code ändern, und das System kann zur Laufzeit auf neue Sensortypen reagieren.

Definition der Sensorschnittstelle

Zunächst wird das abstrakte Produkt definiert – die Sensorschnittstelle, die alle konkreten Handler implementieren müssen –, die die Kernmethoden für den Datenabruf und optional für die Konfigurations- oder Metadatenberichterstattung deklariert.

public interface Sensor {
 /**
 * Retrieves the latest sensor reading.
 * @return a Data object containing timestamp, value, and unit.
 */
 Data getData();

 /**
 * Returns the sensor's unique identifier.
 */
 String getSensorId();

 /**
 * Returns the type of sensor (e.g., "temperature", "pressure").
 */
 String getSensorType();
}

Für ein Produktionssystem können Sie auch Methoden zur Initialisierung, Diagnoseprüfung und Fehlerbehebung einschließen.Die Schnittstelle sollte klein gehalten werden, um sie für jeden Sensortyp einfach zu implementieren.

Erstellen von konkreten Sensorklassen

Jeder Sensortyp erhält seine eigene konkrete Klasse, die implementiert. Diese Klassen kapseln die Logik für die Kommunikation mit dem physischen Sensor, die Analyse seiner Ausgabe und die Umwandlung in ein Standard-Objekt ein.

public class TemperatureSensor implements Sensor {
 private final String sensorId;
 private final String deviceUrl; // e.g., Modbus address or HTTP endpoint

 public TemperatureSensor(String sensorId, String deviceUrl) {
 this.sensorId = sensorId;
 this.deviceUrl = deviceUrl;
 }

 @Override
 public Data getData() {
 // Implementation: read from sensor via Modbus, MQTT, or HTTP
 // Convert raw value to Celsius, wrap in Data object
 return new Data(sensorId, System.currentTimeMillis(), value, "°C");
 }

 @Override
 public String getSensorId() { return sensorId; }

 @Override
 public String getSensorType() { return "temperature"; }
}

public class PressureSensor implements Sensor {
 private final String sensorId;
 private final String mqttTopic;

 public PressureSensor(String sensorId, String mqttTopic) {
 this.sensorId = sensorId;
 this.mqttTopic = mqttTopic;
 }

 @Override
 public Data getData() {
 // Subscribe to MQTT topic, parse JSON payload
 return new Data(sensorId, System.currentTimeMillis(), pressureValue, "bar");
 }
 // ...
}

Indem Sie die Kommunikationsdetails innerhalb der konkreten Klasse halten, isolieren Sie den Rest des Systems vom protokollspezifischen Code. Wenn Sie später einen Modbus-Temperatursensor durch einen I2C-Sensor ersetzen, müssen Sie lediglich ändern; der Fabrik- und Client-Code bleibt unberührt.

Directus für Sensorkonfiguration

Anstatt die Parameter von Hardcoding-Sensoren zu speichern, können wir sie in Directus-Sammlungen speichern.

  • (UUID)
  • (String ‐ “Temperatur”, “Druck”, “Feuchtigkeit”)
  • (String ‐ vollqualifizierter Klassenname, z.B. „com.example.sensors.TemperatureSensor)
  • (JSON-Objekt mit protokollspezifischen Parametern)

Wenn das System initialisiert, holt es die Liste der aktiven Sensoren von Directus ab und wählt mit dem -Feld die entsprechende Fabrik aus. Alternativ können Sie die Fabrikklasse direkt speichern. Dieser Ansatz macht die Sensorflotte über die Directus-Admin-Benutzeroberfläche oder API vollständig konfigurierbar, sodass Nicht-Entwickler Sensoren hinzufügen, entfernen oder ändern können, ohne Code zu berühren.

Umsetzung der Factory-Methode

Jetzt definieren wir den abstrakten Schöpfer – die FLT:15 –, die die Fabrikmethode FLT:16 deklariert. Die Fabrikmethode kann Parameter akzeptieren, die von konkreten Sensoren benötigt werden (wie Sensor-ID und -Konfiguration).

public abstract class SensorFactory {
 /**
 * Factory method – subclasses implement this to create specific sensors.
 * @param sensorId the unique identifier for the sensor
 * @param config additional configuration (e.g., device URL, MQTT topic)
 * @return a Sensor instance
 */
 public abstract Sensor createSensor(String sensorId, Map<String, Object> config);

 /**
 * Optional: method to validate configuration before sensor creation.
 */
 public boolean validateConfig(Map<String, Object> config) {
 return true; // subclasses can override
 }
}

Konkrete Fabrikklassen setzen sich außer Kraft, um den entsprechenden Sensorhandler zu instanziieren. Jede Fabrik weiß, welche Klasse instanziiert werden soll und wie die generische Konfigurationskarte zu interpretieren ist.

public class TemperatureSensorFactory extends SensorFactory {
 @Override
 public Sensor createSensor(String sensorId, Map<String, Object> config) {
 String deviceUrl = (String) config.get("device_url");
 // Could also extract other parameters like polling interval
 return new TemperatureSensor(sensorId, deviceUrl);
 }

 @Override
 public boolean validateConfig(Map<String, Object> config) {
 return config.containsKey("device_url");
 }
}

public class PressureSensorFactory extends SensorFactory {
 @Override
 public Sensor createSensor(String sensorId, Map<String, Object> config) {
 String mqttTopic = (String) config.get("mqtt_topic");
 return new PressureSensor(sensorId, mqttTopic);
 }
}

Factory Registration und Lookup

Um das Factory Method-Muster praktisch zu machen, benötigen Sie einen Mechanismus, um die richtige Factory zur Laufzeit auszuwählen. Ein gängiger Ansatz ist die Aufrechterhaltung einer -Registrierung, die Sensortyp-Strings zu Factory-Instanzen abbildet. Diese Registry kann beim Start durch Scannen eines Pakets nach Factory-Klassen oder – besser – durch Lesen der Zuordnung von Directus gefüllt werden.

public class SensorFactoryRegistry {
 private Map<String, SensorFactory> factoryMap = new HashMap<>();

 public void registerFactory(String sensorType, SensorFactory factory) {
 factoryMap.put(sensorType, factory);
 }

 public SensorFactory getFactory(String sensorType) {
 SensorFactory factory = factoryMap.get(sensorType);
 if (factory == null) {
 throw new IllegalArgumentException("No factory registered for sensor type: " + sensorType);
 }
 return factory;
 }
}

Wenn das System startet, fragt es Directus nach der Liste der verfügbaren Sensortypen und dem entsprechenden Fabrikklassennamen. Dann instanziiert es jede Fabrik und registriert sie in der Registrierung. Danach ist die Verarbeitung eines neuen Sensors so einfach wie:

// Example: handling an incoming sensor registration message
String sensorType = message.getType();
String sensorId = message.getId();
Map<String, Object> config = message.getConfig();

SensorFactory factory = registry.getFactory(sensorType);
Sensor sensor = factory.createSensor(sensorId, config);
// Use sensor to start reading data...

Dieses Muster hält den Clientcode (die Datenaufnahme-Engine) völlig unabhängig von den konkreten Sensorklassen.Sie können einen neuen Sensortyp einführen, indem Sie einen neuen Handler, eine neue Fabrik schreiben und die Directus-Konfiguration aktualisieren.

Die Factory-Methode in der Praxis anwenden

Gehen wir durch ein realistisches End-to-End-Szenario. Stellen Sie sich eine Fabrikhalle mit Temperatur-, Druck-, Feuchtigkeits- und Vibrationssensoren vor. Zunächst werden nur Temperatur und Druck benötigt. Sie implementieren und mit ihren jeweiligen Fabriken. Die Directus-Kollektion enthält zwei Einträge:

  • [25], [26]
  • [27], [28]

Ihr Startcode liest diese Einträge, instanziiert jede Fabrik mit Hilfe von Reflexion (oder durch einen einfachen Schalter, wenn Sie es vorziehen) und speichert sie in der Registrierung. Wenn ein Temperatursensor eine Registrierungsanfrage sendet (z. B. über MQTT), sucht das System die "Temperatur" -Fabrik, ruft mit der Sensor-ID und -Konfiguration von Directus auf und fügt das resultierende -Objekt einer Umfrage- oder Abonnementschleife hinzu. Alles funktioniert reibungslos.

Einen Monat später installiert die Anlage Vibrationssensoren. Ein Entwickler schreibt und und fügt dann einen neuen Eintrag in Directus für hinzu. Ohne das System zu stoppen, nimmt der Startcode (oder eine Live-Konfigurations-Reload-Funktion) die neue Fabrik auf. Jetzt kann das System auch Vibrationsdaten verarbeiten - keine Änderungen am Ingestion-Engine, keine Neustarts, keine Neuzustellungen.

Handhabung von Konfiguration und Dependency Injection

In einem Produktionssystem benötigen Fabriken oft Zugriff auf externe Abhängigkeiten wie Datenbankverbindungen, Nachrichtenbroker oder Directus API-Clients. Das Factory Method-Muster kann erweitert werden, um die Abhängigkeitsinjektion zu unterstützen, indem man einen Kontext oder Container an Fabriken weiterleitet.

public abstract Sensor createSensor(String sensorId, Map<String, Object> config, SensorContext context);

Das Objekt FLT:35 bietet gemeinsam genutzte Ressourcen wie Protokollierung, Metriken und Datenpersistenz. Konkrete Fabriken können diese dann an die Sensorhandler weitergeben. Dies hält das Muster flexibel und stellt sicher, dass Sensorinstanzen Zugriff auf die erforderlichen Dienste haben, ohne auf globale Singletons zurückzugreifen.

Integration mit Directus Data Flow

Directus kann auch als Speicher-Backend für die Sensordaten selbst dienen. Nachdem die Fabrik einen Sensor-Handler erstellt hat, kann der Handler Daten lesen und über seine REST- oder GraphQL-API in Directus schreiben. Zum Beispiel könnte die -Methode das Lesen in eine -Sammlung in Directus verschieben. Dies schafft eine saubere Trennung: Der Sensor-Handler weiß nur, wie er die Daten erfasst, während das CMS Speicher, Zugriffskontrolle und Präsentation übernimmt.

Darüber hinaus können Sie mit den Event-Hooks oder Webhooks von Directus eine Echtzeit-Verarbeitung auslösen, wenn Sensordaten hinzugefügt werden. Das Factory-Methodenmuster stellt sicher, dass das System im Zuge der Entwicklung der Sensorflotte erweiterbar bleibt.

Vorteile der Verwendung des Factory Method Pattern

Der Hauptvorteil der Anwendung des Factory Method-Musters auf die Sensordatenverwaltung ist die -Kapselung der Erstellungslogik. Anstatt den Hauptanwendungscode mit bedingten Anweisungen wie zu verstreuen, delegieren Sie diese Entscheidung an die Fabrikhierarchie. Dies hat mehrere konkrete Vorteile:

  • Erweiterbarkeit ohne Modifikation – Neue Sensortypen können durch die Erstellung neuer Produkte und Fabriken hinzugefügt werden, ohne den bestehenden Clientcode zu ändern.
  • Reduzierte Kopplung – Der Client-Code hängt nur von der -Schnittstelle und der -Abstraktklasse ab. Er hat keine Kenntnis von konkreten Implementierungen, was das System einfacher macht, umzugestalten und zu testen.
  • Wiederverwendbarkeit von Fabriken – Fabriken können in verschiedenen Teilen des Systems wiederverwendet werden.
  • Zentralisierte Konfiguration – In Kombination mit Directus wird die Sensor-Typ-zu-Fabrik-Zuordnung extern gespeichert, was eine dynamische Rekonfiguration ohne Codeänderungen ermöglicht.
  • Vereinfachtes Testen – Sie können Sensorfabriken in Unit-Tests simulieren oder stuben, wodurch die getestete Logik von den tatsächlichen Hardwareabhängigkeiten isoliert wird. Konkrete Sensorhandler können einzeln mit simulierter Hardware getestet werden.
  • Konsistentes Lifecycle-Management – Fabriken können konsistente Initialisierungs- und Validierungslogik erzwingen. Wenn eine Sensorkonfiguration ungültig ist, kann die Fabrik sie ablehnen, bevor ein Sensorobjekt erstellt wird, wodurch halbinitialisierte Zustände vermieden werden.

Mögliche Nachteile und Abschwächungen

Die Factory-Methode kann zu einer Explosion von Klassen führen (ein Produkt + eine Fabrik pro Sensortyp). In einem System mit Hunderten von Sensortypen kann dies umständlich werden.

  • Verwendung einer parametrisierten Factory-Methode, die verschiedene Sensorimplementierungen basierend auf einer Typzeichenfolge zurückgibt (ein vereinfachter „Simple Factory-Ansatz), wenn die Anzahl der Typen klein und stabil ist.
  • Durch die Nutzung dynamischer Klassenbelastungen (Reflexion) reduzieren Sie die Boilerplate - achten Sie jedoch auf die Sicherheit und Leistung der Typs.
  • Gruppierung ähnlicher Sensoren unter einer einzigen Fabrik (z. B. ein FLT: 42), das sowohl Thermoelement- als auch RTD-Sensoren erzeugt und die Konfiguration zur Unterscheidung verwendet.

Insgesamt überwiegen die Vorteile in der Regel die zusätzliche Komplexität für Systeme, von denen erwartet wird, dass sie sich weiterentwickeln und wachsen.

Best Practices für die Umsetzung

1. Halten Sie das Produktinterface fokussiert

Eine Sensorschnittstelle sollte nur die wesentlichen Methoden angeben, die für die Datenerfassung und -identifizierung erforderlich sind. Vermeiden Sie es, sie mit Dienstprogrammmethoden oder protokollspezifischen Details aufzublähen. Zusätzliche Funktionen können durch Dekorateure, Strategieobjekte oder zusätzliche Schnittstellen bereitgestellt werden.

2. Fabriken für komplexe Konstruktionen verwenden

Wenn ein Sensorhandler mehrere Abhängigkeiten benötigt (Kommunikationsclient, Datenserialisierer, Kalibriermathematik), ist die Fabrik der perfekte Ort, um sie zusammenzubauen.

3. Validierung von Konfigurationen in Fabriken

Die Fabriken sollten validieren, dass die Konfigurationskarte alle erforderlichen Schlüssel enthält und dass die Werte vom richtigen Typ sind.

4. Verwalten des Factory Lifecycle

Fabriken selbst können einen Zustand haben (z. B. einen zwischengespeicherten Verbindungspool). Wenn ja, stellen Sie sicher, dass sie ordnungsgemäß initialisiert und entsorgt werden.

5. Integration in Monitoring und Logging

In einem Engineering-System ist es wichtig zu wissen, welche Sensoren instanziiert wurden und welche Fabriken aktiv sind. Fügen Sie die Protokollierung der Fabrikmethoden hinzu, um Sensorerstellungsereignisse aufzuzeichnen, und legen Sie Metriken (z. B. die Anzahl der Sensoren pro Typ) durch ein Überwachungstool wie Prometheus frei.

6. Fabrik-zu-Typ-Mappings extern speichern

Verwenden Sie Directus oder einen ähnlichen Konfigurationsspeicher, um das Mapping statt Hardcoding zu speichern. Dies ermöglicht Laufzeit-Updates und gibt Nicht-Entwicklern die Möglichkeit, Sensortypen zu verwalten.

Beispiel aus der realen Welt: Aufbau eines Flottensensor-Managementsystems mit Directus

Betrachten Sie zur Veranschaulichung des Gesamtansatzes ein System, das Sensoren über mehrere Standorte hinweg verwaltet.

  • Sensordefinitionen speichern (Typ, Handlerklasse, config JSON).
  • Dauerhafte Sensormessungen.
  • Bereitstellung einer Dashboard-Benutzeroberfläche für Bediener.

Das Java/Spring Boot Backend beginnt damit, dass es von Directus alle aktiven abruft. Für jeden Typ instanziiert es die Fabrik mit Hilfe von Reflexion (der Name der Fabrikklasse wird in der Datenbank gespeichert).

Wenn ein neuer physischer Sensor online geht, sendet er eine Registrierungsnachricht über MQTT. Das Backend empfängt die Nachricht, extrahiert den Sensortyp und die ID, sucht die entsprechende Fabrik aus der Registry und ruft mit der ID und Konfiguration (auch von Directus abgerufen) auf. Das resultierende -Objekt wird in einem gespeichert, das durch die Sensor-ID eingegeben wird. Eine geplante Aufgabe ruft dann periodisch auf jedem aktiven Sensor auf und stellt die Lesung an Directus.

Diese Architektur hat sich als extrem widerstandsfähig gegenüber Veränderungen erwiesen. Wenn ein neuer Sensortyp entwickelt wird, muss das Team nur den Handler und die Fabrik schreiben, dann einen Datensatz in Directus hinzufügen. Das System nimmt ihn automatisch beim nächsten Aktualisierungszyklus (oder bei Bedarf über einen REST-Endpunkt) auf. Der gesamte Prozess ist schlank, testbar und auf moderne DevOps-Praktiken ausgerichtet.

Externe Ressourcen

Für weitere Informationen über das Factory Method-Muster und seine Anwendung in Engineering-Systemen, betrachten Sie diese Artikel:

Schlussfolgerung

Das Factory Method-Muster bietet eine bewährte Lösung für die Verwaltung der Objekterstellung in Systemen, die eine Vielzahl von Sensortypen unterstützen müssen. Durch die Entkopplung der Instanziationslogik von der Sensorhandler-Implementierung können Ingenieure Systeme erstellen, die für die Erweiterung offen und für die Modifikation geschlossen sind.

In Kombination mit einer flexiblen Datenplattform wie Directus erreicht das Muster sein volles Potenzial. Directus fungiert als dynamischer Konfigurationsspeicher, der die Werksauswahl zur Laufzeit steuert, Nullcode-Sensorzusätze und eine zentrale Verwaltung der gesamten Sensorflotte ermöglicht. Das Ergebnis ist ein robustes, skalierbares und wartbares Engineering-Monitoring-System, das sich neben der überwachten Technologie weiterentwickeln kann.

Egal, ob Sie eine IoT-Plattform für eine Smart Factory, ein Umweltüberwachungsnetzwerk oder ein Labordatenerfassungssystem erstellen, das Factory Method-Muster bietet in Kombination mit Directus die architektonische Grundlage, um mit verschiedenen Sensordaten effizient und flexibel umzugehen.