Open Source im professionellen Einsatz

Design Patterns

Entwurfsmuster [4] gehören schon seit Jahren zum Repertoire des professionellen Programmierers. Es überrascht nicht, dass Dart darauf setzt. Das Factory Pattern beispielsweise ist bereits Bestandteil der Sprache: Stellt der Entwickler einem Konstruktor das Schlüsselwort »factory« voran, erzeugt Dart nicht automatisch selbst ein Objekt dieser Klasse, sondern überlässt das dem Konstruktor. In diesem kann der Programmierer dann beispielsweise in einem Cache nachsehen, ob schon ein passendes Objekt existiert – genau wie in Listing 6: »nocheinauto« verweist hier auf dasselbe Objekt wie »einauto« . Aufgrund des Schlüsselworts »static« existiert »garage« nur ein einziges Mal, alle »Auto« -Objekte greifen auf dieselbe Variable zu.

Listing 6

Factory Pattern

01 class Auto {
02         String gefertigtvon;
03         static Map garage;
04
05         factory Auto(String hersteller) {
06                 if(Auto.garage == null) Auto.garage=new Map();
07
08                 if(Auto.garage.containsKey(hersteller)!=null) return Auto.garage[hersteller];
09                 else {
10                         Auto neuesauto = new Auto.kaufen(hersteller);
11                         Auto.garage[hersteller] = neuesauto;
12                         return neuesauto;
13                 }
14         }
15
16         Auto.kaufen(this.gefertigtvon);
17 }
18
19 main() {
20         var einauto = new Auto("Ferrari");
21         var nocheinauto = new Auto("Ferrari");
22 }

Das Factory Pattern lässt sich zudem noch mit Interfaces kombinieren. Dazu weist der Programmierer einem Interface eine Standard-Factory-Klasse zu, die wiederum zum Interface passende Objekte zurückliefert. Listing 7 zeigt dazu ein Beispiel. Das Interface legt dabei die Signatur des Konstruktors fest, der dann zum Interface passende Objekte ausgibt. Die »AutoFabrik« liefert abhängig vom ihr übergebenen »hersteller« entweder ein »Rennwagen« - oder ein »Mittelklasse« -Objekt. Bei der Instanzierung in »main()« sieht es dann so aus, als würde man direkt ein »Auto« anlegen.

Listing 7

Kombination von interface und factory

01 interface Auto default AutoFabrik {
02     Auto(hersteller);
03     final hersteller;
04 }
05
06 class AutoFabrik {
07         factory Auto(hersteller) {
08                 if (hersteller == "Ferrari") {
09                         return new Rennwagen(hersteller);
10                 }
11                 return new Mittelklasse(hersteller);
12         }
13 }
14
15 class Rennwagen implements Auto {
16         Rennwagen(this.hersteller);
17         String hersteller;
18 }
19
20 class Mittelklasse implements Auto {
21         Mittelklasse(this.hersteller);
22         String hersteller;
23 }
24
25 main() {
26     print(new Auto("Ferrari") is Rennwagen);
27     print(new Auto("VW") is Rennwagen);
28 }

Wie in Listing 7 ebenfalls zu sehen ist, prüft das Schlüsselwort »is« , ob ein Objekt von einem bestimmten Typ ist. Das Schlüsselwort »final« vor »hersteller« sorgt übrigens dafür, dass sich der Variablen nur genau einmal bei ihrer Initialisierung ein Wert zuweisen lässt.

Dart enthält die aus Java bekannten generischen Typen alias Generics. C++-Programmierer kennen das Konzept als Templates. Mit ihnen lassen sich schnell Container für beliebige Objekte schaffen. Die eingebauten Listen und Maps sind bereits von Haus aus generische Typen. So erzeugt etwa »List<Auto>« eine Liste für Auto-Objekte (Listing 8).

Listing 8

Generische Typen

01 main() {
02         List<Auto> autoliste = new List<Auto>();
03         autoliste.add(new Auto("Ferrari"));
04         Auto einauto = autoliste[0];
05 }

Da Variablen beliebige Inhalte aufnehmen, sperrt sich Dart allerdings auch nicht gegen Folgendes:

List<Auto> autoliste = new List<Auto>();
List<LKW> lkwliste = autoliste;

Dieser Versuch fliegt dem Entwickler aber später vielleicht um die Ohren, wenn er etwas mit den vermeintlichen LKWs aus der »lkwliste« anstellen möchte.

Nebenläufigkeit

Parallel zu erledigende Aufgaben lagert der Programmierer normalerweise in je einen separaten Thread aus und versucht mit viel Hirnschmalz und Verwaltungsaufwand deren Zwischenergebnisse zusammenzuführen. Dem nimmt Dart den Schrecken: Ein von der Basisklasse »Isolate« abgeleitetes Objekt läuft auf Wunsch isoliert neben dem Hauptprogramm in einem eigenen Thread.

Um miteinander Zwischenergebnisse auszutauschen, können sich solche Isolates gegenseitig Nachrichten schicken. Die landen zunächst in einer Warteschlange, bis sie das empfangende Isolate über einen so genannten Port abholt. Dieses Konzept lehnt sich stark an das Aktoren-Modell aus Erlang beziehungsweise Scala an. Listing 9 zeigt ein komplettes Beispiel dafür.

Listing 9

Kommunikation mit einem Isolate

01 class Empfaenger extends Isolate {
02         main() {
03                 port.receive((nachricht, replyTo) {
04                         if (nachricht == null) port.close();
05                         else print("Empfange: ${nachricht}");
06                 });
07         }
08 }
09
10 main() {
11         new Empfaenger().spawn().then((port) {
12                 for (var nachricht in ['Dies', 'ist', 'ein', 'Test']) {
13                         port.send(nachricht);
14                 }
15                 port.send(null);
16         });
17 }

Zunächst erstellt das Beispielprogramm ein neues »Empfaenger« -Objekt, das es via »spawn()« in einen eigenen Thread verfrachtet. Anschließend sendet es dem Objekt nacheinander vier Wörter. Sobald das Objekt ein Wort empfängt, schreibt es dieses auf den Bildschirm. Das Isolate bekommt übrigens mit »replyTo« immer einen Port zum Objekt übergeben, das ihm die Nachricht geschickt hat. Damit kann es dann direkt seinem Auftraggeber antworten.

Isolates laufen in getrennten Speicherbereichen. Das hat den angenehmen Nebeneffekt, dass die Garbage Collection jedes Isolate individuell behandeln kann. Im Gegenzug muss die virtuelle Maschine die Nachrichten zwischen den Isolates kopieren. Künftig sollen Isolates sogar unterschiedliche Dart-Bibliotheken in verschiedenen Versionen nutzen können.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 5 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook