Hallo zusammen,
da ich aktuell ein wenig Zeit für mich zur Verfügung habe, ist es mir möglich mein IoT-System zu überarbeiten und auszubauen. Dafür habe ich mir überlegt, das Gesamtkonzept umzustellen, worauf ich jedoch heute noch nicht eingehen möchte. Bevor ich mit der Umstrukturierung beginnen kann, möchte ich noch ein paar Altlasten loswerden, welche ich bei der ersten Programmierung des Systems erzeugt habe. Auf eine dieser Lasten möchte ich heute eingehen.
Als eines der grundlegendsten Elemente in der Programmierung des gesamten Systems existiert die Enumeration "IoTValueType". Eine Enumeration ist - einfach gesagt - ein Datentyp, welcher nur definierte Werte annehmen kann. Ein gutes Beispiel dafür ist ein Wochentag. Eine Enumeration vom Typ "Wochentag" kann logisch nur die Werte "Montag", "Dienstag", ... "Sonntag" annehmen. (mehr) Im Hintergrund kümmert sich dann der Compiler darum, dass jedem Enumerationswert ein passender Ganzzahlwert zugeordnet wird. Diese Zuordnung kann auch per Hand durchgeführt werden.
Enumerationen können auch dafür genutzt werden, um mehrere der definierten Werte auszuwählen. Um beim gleichen Beispiel zu bleiben, könnte mit Hilfe der Enumeration "Wochentag" eine Auswahl erstellt werden, an welchen Tagen beispielsweise ein Wecker klingeln soll. Dafür muss die Enumeration mit dem "Flags-Attribut" markiert werden. Im Normalfall wird jedem Enumerationswert eine Ganzzahl zugeordnet:
Mit dem Flags-Attribut wird jedem Wert ein Bit zugeordnet, wodurch sie praktisch Werte der Zweierpotenzreihe annehmen:
Dadurch ist es nun möglich, Kombinationen zu bilden. Beispielsweise entspricht die Auswahl "Dienstag und Mittwoch" gleich der Zahl 6. Ohne das Flags-Attribut ergibt dieselbe Kombination die Zahl 3, welcher bereits "Donnerstag" zugeordnet ist. Es kann daher nicht unterschieden werden, ob bei einer 3 "Donnerstag" oder "Dienstag und Mittwoch" gemeint ist.
Ich habe nun bisher eine solche Enumeration verwendet, um die möglichen Datentypen im System zu definieren. Dadurch ist es nicht nur möglich gewesen, den genauen Datentyp eines Elements festzulegen, sondern mit Hilfe des Flags-Attributes auch eine Auswahl an Typen anzugeben, welche von einem Element unterstüzt werden. Dies habe ich insbesondere bei der Erstellung der Logikstrukturen verwendet, wie ich in einem früheren Post beschrieben habe.
Die Verwendung einer Enumeration an dieser Stelle hat jedoch den Nachteil, dass die Auswahl an Datentypen auf die angegebenen Typen begrenzt ist. Eine Erweiterung ist daher nur möglich, indem neue Typen der Enumeration hinzugefügt werden. Ich habe zwar auch einen Datentyp "Objekt" hinzugefügt, welcher einen beliebigen Datentyp beschreibt, dies führt jedoch dazu, dass Elemente mit verschiedenen Objekt-Datentypen verknüpft werden können. Ein weiterer negativer Punkt ist, dass keine Arrays o.Ä. existieren. Arrays können zwar auch über den Objekt-Datentyp übergeben werden, aber das führt wieder zu dem eben genannten Verhalten.
Um die aufgezeigten Probleme zu lösen, habe ich beschlossen die Enumeration "IoTValueType" zu ersetzen. Dafür habe ich mir zunächst überlegt, welche Arten von Datentypen es gibt und wie diese zu differenzieren sind. Grundsätzlich resultieren daraus drei Arten: Ein Grunddatentyp, welcher einfache Werte wie Ganzzahlen, Strings, etc. darstellt, ein Arraydatentyp, welcher eine Auflistung von Werten eines Datentyps darstellt und ein komplexer Datentyp, welcher eine Zusammenstellung verschiedener Datentypen darstellt. Die genannten Datentypen habe ich nun durch Klassen beschrieben, welche alle eine gemeinsame "DataType"-Basisklasse verwenden.
Neben den im Bild dargestellten Feldern besitzt die DataType-Basisklasse noch weitere Felder und Methoden, um beispielsweise einem Datentyp Methoden zum Serialisieren und Deserialisieren zuzuordnen.
Die Verwendung der genannten DataType-Klasse hat aber nun den Nachteil, dass jeweils nur exakt ein Datentyp verwendet werden kann. Daher habe ich zusätzlich eine Klasse MultiDataType angelegt, welche es ermöglicht mehrere mögliche Datentypen anzugeben.
da ich aktuell ein wenig Zeit für mich zur Verfügung habe, ist es mir möglich mein IoT-System zu überarbeiten und auszubauen. Dafür habe ich mir überlegt, das Gesamtkonzept umzustellen, worauf ich jedoch heute noch nicht eingehen möchte. Bevor ich mit der Umstrukturierung beginnen kann, möchte ich noch ein paar Altlasten loswerden, welche ich bei der ersten Programmierung des Systems erzeugt habe. Auf eine dieser Lasten möchte ich heute eingehen.
Enumerationen
Als eines der grundlegendsten Elemente in der Programmierung des gesamten Systems existiert die Enumeration "IoTValueType". Eine Enumeration ist - einfach gesagt - ein Datentyp, welcher nur definierte Werte annehmen kann. Ein gutes Beispiel dafür ist ein Wochentag. Eine Enumeration vom Typ "Wochentag" kann logisch nur die Werte "Montag", "Dienstag", ... "Sonntag" annehmen. (mehr) Im Hintergrund kümmert sich dann der Compiler darum, dass jedem Enumerationswert ein passender Ganzzahlwert zugeordnet wird. Diese Zuordnung kann auch per Hand durchgeführt werden.
Enumerationen können auch dafür genutzt werden, um mehrere der definierten Werte auszuwählen. Um beim gleichen Beispiel zu bleiben, könnte mit Hilfe der Enumeration "Wochentag" eine Auswahl erstellt werden, an welchen Tagen beispielsweise ein Wecker klingeln soll. Dafür muss die Enumeration mit dem "Flags-Attribut" markiert werden. Im Normalfall wird jedem Enumerationswert eine Ganzzahl zugeordnet:
(Montag = 0, Dienstag = 1, Mittwoch = 2, Donnerstag = 3, Freitag = 4, ...)
Mit dem Flags-Attribut wird jedem Wert ein Bit zugeordnet, wodurch sie praktisch Werte der Zweierpotenzreihe annehmen:
(Montag = 1, Dienstag = 2, Mittwoch = 4, Donnerstag = 8, Freitag = 16, ...)
Dadurch ist es nun möglich, Kombinationen zu bilden. Beispielsweise entspricht die Auswahl "Dienstag und Mittwoch" gleich der Zahl 6. Ohne das Flags-Attribut ergibt dieselbe Kombination die Zahl 3, welcher bereits "Donnerstag" zugeordnet ist. Es kann daher nicht unterschieden werden, ob bei einer 3 "Donnerstag" oder "Dienstag und Mittwoch" gemeint ist.
Ich habe nun bisher eine solche Enumeration verwendet, um die möglichen Datentypen im System zu definieren. Dadurch ist es nicht nur möglich gewesen, den genauen Datentyp eines Elements festzulegen, sondern mit Hilfe des Flags-Attributes auch eine Auswahl an Typen anzugeben, welche von einem Element unterstüzt werden. Dies habe ich insbesondere bei der Erstellung der Logikstrukturen verwendet, wie ich in einem früheren Post beschrieben habe.
IoTValueType-Enumeration |
DataType - Klasse
Um die aufgezeigten Probleme zu lösen, habe ich beschlossen die Enumeration "IoTValueType" zu ersetzen. Dafür habe ich mir zunächst überlegt, welche Arten von Datentypen es gibt und wie diese zu differenzieren sind. Grundsätzlich resultieren daraus drei Arten: Ein Grunddatentyp, welcher einfache Werte wie Ganzzahlen, Strings, etc. darstellt, ein Arraydatentyp, welcher eine Auflistung von Werten eines Datentyps darstellt und ein komplexer Datentyp, welcher eine Zusammenstellung verschiedener Datentypen darstellt. Die genannten Datentypen habe ich nun durch Klassen beschrieben, welche alle eine gemeinsame "DataType"-Basisklasse verwenden.
Datenstruktur "DataType" |
MultiDataType
Die Verwendung der genannten DataType-Klasse hat aber nun den Nachteil, dass jeweils nur exakt ein Datentyp verwendet werden kann. Daher habe ich zusätzlich eine Klasse MultiDataType angelegt, welche es ermöglicht mehrere mögliche Datentypen anzugeben.
using System; using System.Collections.Generic; using System.Linq; using HomeAutomationServerExtensionInterface; namespace LogicStructureEditor { public class MultiDataType {
Das Prinzip des MultiDataType besteht darin, dass es zunächst vier Zustände besitzt. Diese sind "Alle", "Keine", "Alle außer" und "Keine außer". Bei der Nutzung einer der letzten beiden Zustände wird außerdem eine Liste verwendet, welche die Datentypen enthält, welche zulässig oder eben nicht zulässig sind.
Zudem definiert die Klasse Operatoren zum Vergleich und die Bitoperatoren OR, AND und die Bitweise-Negation. Diese werden verwendet, um das Verhalten der Enumeration des alten IoTValueType weiterverwenden zu können. Dadurch kann ein Großteil des geschriebenen Quellcodes weiterverwendet werden. Trotzdem war es nötig, große Teile des Quellcodes zu überarbeiten. Die Überarbeitung ist aber nun abgeschlossen und mein System läuft mit der überarbeiteten Variante.
Im nächsten Schritt werde ich die Anfangs erwähnte Umstrukturierung des Systems angehen. Dazu werde ich mich hier äußern, wenn ich dies abgeschlossen habe.
Bis dahin,
Markus
Zudem definiert die Klasse Operatoren zum Vergleich und die Bitoperatoren OR, AND und die Bitweise-Negation. Diese werden verwendet, um das Verhalten der Enumeration des alten IoTValueType weiterverwenden zu können. Dadurch kann ein Großteil des geschriebenen Quellcodes weiterverwendet werden. Trotzdem war es nötig, große Teile des Quellcodes zu überarbeiten. Die Überarbeitung ist aber nun abgeschlossen und mein System läuft mit der überarbeiteten Variante.
Im nächsten Schritt werde ich die Anfangs erwähnte Umstrukturierung des Systems angehen. Dazu werde ich mich hier äußern, wenn ich dies abgeschlossen habe.
Bis dahin,
Markus
Keine Kommentare:
Kommentar veröffentlichen