Montag, 21. Dezember 2015

Akka.NET Adventskalender – Tag 21

Was der Franke unter "blägn" versteht

Während der vergangenen Sprints haben wir uns immer an einzelne bekannte Aktoren gewandt, wenn wir Nachrichten verschickt haben. Diese Woche werden wir uns eine weitere Benachrichtigungs-Strategie ansehen: Ausstrahlung (Broadcast). Das bedeutet, dass wir einen Absender einer Nachricht und keinen, einen oder beliebig viele Empfänger dieser Nachricht haben werden.

Dieses Muster wird auch als "Publish/Subscribe" bezeichnet. Selbstverständlich beherrscht Akka.NET auch dieses Muster. Diesmal werden wir nicht nochmal das Rad neu erfinden, indem wir dieses Muster nachprogrammieren. Stattdessen werden wir direkt die Möglichkeiten nutzen, die wir standardgemäß zur Verfügung haben.

Um eine Nachricht oder ein Ereignis (Ereignisse waren definiert als etwas vergangenes, daher nutzen wir in solchen Fällen gerne die Vergangenheit beim Verb) ausstrahlen möchten, sieht das so aus:

Context.System.EventStream.Publish(new SomethingHappened());

Wenn wir auf ein Ereignis oder eine Nachricht lauschen wollen, dann können wir eine dieser Methoden dazu einsetzen:

protected override void PreStart()
{
    // the most basic way of subscribing
    Context.System.EventStream.Subscribe(Self, typeof(SomethingHappened));
 
    // if you are `using Akka.Event;` you might also do:
    Context.System.EventStream.Subscribe<SomethingHappened>(Self);
}

Um zu demonstrieren, wie leistungsfähig das Ausstrahlen und Abonnieren von Nachrichen ist, werden wir ein kleines Sudoku Spiel zusammen programmieren. Die Idee dazu kam mir kürzlich nach einem Event-Storming Workshop, bei dem knapp 20 Personen im Raum scheinbar planlos umherschossen und am Ende ein durchdachtes Konzept an der Tafel stand. Faszinierend :-)

Und genau so können wir beim Sudoku vorgehen. Wir setzen in jedes einzelne Feld einen Aktor, der für genau dieses Feld zuständig ist. Jeder dieser Aktoren schnappt wertvolle Hinweise darüber auf, ob in seiner Zeile, seiner Spalte oder seinem Block etwas verändert wurde und streicht eventuell eben gesetzte Ziffern von seiner Liste der noch zur Verfügung stehenden Möglichkeiten. Bleibt nur noch eine Ziffer übrig, so ist diese Zelle gelöst. Das wiederum erfahren alle anderen und so löst sich das Rätsel schrittweise von selbst.

Da wir noch mehr Aktoren brauchen werden, packen wir die von allen gemeinsam genutzten Funktionalitäten in eine Basisklasse (morgen gibt es wieder ein github Repository). In dieser Basisklasse verhalten wir uns auch sehr tolerant, indem wir nicht verarbeitete Ereignisse einfach ignorieren. Normalerweise sollte man sich so etwas wirklich gut überlegen.

using Akka.Actor;
using Akka.Event;
using SudokuSolver.Messages;

namespace SudokuSolver.Actors
{
    /// 
    /// Base class for all Sudoko actors
    /// 
    public class SudokuActor : ReceiveActor
    {
        private readonly IActorRef printActor;

        public SudokuActor(IActorRef printActor)
        {
            this.printActor = printActor;
        }

        protected override void PreStart()
        {
            Context.System.EventStream.Subscribe<SetDigit>(Self);
        }

        protected void Publish(object message)
        {
            Context.System.EventStream.Publish(message);
        }

        protected override void Unhandled(object message)
        {
            // we do nothing, just ignore unhandled messages
        }
    }
}

und natürlich müssen wir die Nachricht definieren, die die Ziffer einer Zelle setzt. Darauf lauschen ja alle Zellen und ziehen ihre Schlußfolgerungen.

namespace SudokuSolver
{
    public class SetDigit
    {
        public int Row { get; set; }
        public int Col { get; set; }
        public int Block { get { return Row / 3 * 3 + Col / 3; } }

        public int Digit { get; set; }

        public SetDigit(int row, int col, int digit)
        {
            Row = row;
            Col = col;
            Digit = digit;
        }
    }
}

Wie wir dann tatsächlich das Sudoku lösen, verrate ich euch morgen.

Keine Kommentare:

Kommentar veröffentlichen