So,
habe mich ein wenig mit dem Code und den Konzepten auseinander gesetzt und kann jetzt endlich meinen unqualifizierten Senf dazu geben. Vorsicht, ab hier wird es für Nicht-Entwickler wahrscheinlich etwas kryptisch.
Grundsätzlich denke ich, wir sollten uns Modell vom Prozess der Konstruktion trennen: Wir brauchen ein möglichst einfaches, möglichst intuitives API, mit dem man einen Kalender definieren kann. Mir hat der erste Wurf von 1of3 sehr gut gefallen, und aus meiner Sicht wäre es wünschenswert, wenn das Skript für die Definition eines Kalenders so simpel bleiben könnte. Die gute Nachricht ist: Ich bin mir ziemlich sicher, das das auch klappt, aber dazu später mehr. Unabhängig von dieser Builder-API brauchen wir eine Datenstruktur, die die Domäne möglichst treffend abbildet. Wir haben also so gesehen zwei (oder mehr - auch dazu später mehr) "Pakete": Das Builder API und das Domänenmodell. Das Builder API definiert Funktionen, die - so sie aufgerufen werden - Objekte aus dem Domänenmodell erzeugen.
Für das Builder API bauen wir eine möglichst gut lesbare DSL (wie ja schon geschehen / bzw. begonnen)
Für das Domänenmodell modellieren wir so schnörkellos wie möglich unsere Anwendungsdomäne. Wir brauchen also geeignete Klassen, die die einzelnen Informationen, welche einen Kalender beschreiben, sowie die Beziehungen zwischen diesen Informationen möglichst einfach abbilden.
Wir sollten allerdings denke ich vermeiden, die Logik zur Konstruktion unserer Modellobjekte mit eben diesen Objekten zu vermischen: Die Definition eines Kalenders ist ein halbwegs komplexer Prozess, es lohnt sich diesen von der Repräsentation der Daten zu trennen, die von ihm (dem Prozess) erzeugt wird. Dazu verwendet man in der Regel das
Builder Pattern. Selbiges ist ziemlich formalistisch definiert, weil es in der GoF-Bibel steht, aber so genau muss man das nicht nehmen. Wichtig ist die Essenz: Trenne einen komplexen Erzeugungs-Prozess vom (am Ende dieses Prozesses stehenden) Produkt. Ein Auto weiß nichts über den komplizierten Prozess, der durchlaufen werden musste, um es herzustellen, ebenso verhält es sich mit unserem Kalender.
Was das Builder API angeht, gefällt mir wie gesagt der ursprüngliche Vorschlag nach wie vor sehr gut, und ich denke auch, dass wir uns davon nicht weit entfernen müssen. Tage sind zwar sicherlich eine zu grobe Zeiteinheit für ein flexibles Kalendersystem, jedoch denke ich, dass in >95% aller klassichen RPG-Settings zumindest mal gilt, dass eine Stunde 60 Minuten und eine Minute 60 Sekunden hat. Selbst der 24-Stunden-Tag ist sehr weit verbreitet. Ich meine, dass diese Werte sich daher als
sensible defaults anbieten - sie sind genau das, was in 95% zutrifft, von daher sollte es so einfach wie möglich sein, einen Kalender mit diesen Standardwerten zu erzeugen. Natürlich gibt es die Ausnahmen, und die sind auch nicht so extrem, dass man sie ignorieren könnte: Die Rotationsgeschwindigkeit von Planeten wird in Scifi-Settings häufig explizit definiert. Das Builder API sollte es also möglich machen, Tage mit 20 oder 32 Stunden zu definieren - oder Hell-Dunkel-Zyklen, die Soliden heißen und jeweils 4 Quartäre haben, welche unterteilt werden in jeweils 10000 Decamils. Dies sollte nach Möglichkeit ebenfalls mit dem Builder API relativ einfach zu beschreiben sein, da es sich bei solchen Konstrukten aber sicherlich um Exoten handelt, ist es aus meiner Sicht ok, wenn diese Spezialfälle eine etwas umständlichere Beschreibung durch die DSL erfordern. Für den Standardfall sollte es aber z.B. nicht nötig sein explizit zu definieren, dass ein Tag 24 Stunden zu 60 Minuten zu 60 Sekunden hat. Analog dazu plädiere ich für Convenience-Funktionen überall dort, wo es einen Fall gibt, den man in der überwältigenden Mehrheit der Fälle als Standard annehmen kann. Beispiel Events: Meist dürfte es sich hier um einen Tag - z.B. einen Feiertag handeln, insofern wäre es ein
sensible default, von einer Dauer von einem Tag auszugehen. Ich denke auch, dass man standardmäßig annehmen kann, dass ein solcher Event sowohl vorwärts als auch rückwärts wiederholt werden sollte. Auch hier gibt es bestimmt genügend gute Beispiele für Ausnahmen, aber ich denke, unter dem Strich ist das API mit solchen Annahmen meistens einfacher zu verwenden.