let’s dev

Blog

Top!

let’s dev | Scroll to top
let’s dev | Scroll to next content item

Hello

let’s dev | Scroll to previous content item
let’s dev Blog | State Design Pattern in Android
by Thomas
17. September 2018

State Design Pattern in Android

In der modernen Softwareentwicklung sind Design Patterns nicht mehr wegzudenken. Sie ermöglichen Entwicklern auf einer höheren Ebene zu kommunizieren, ohne auf Implementierungsdetails eingehen zu müssen. Im nachfolgenden Beitrag wird im speziellen das State Design Pattern betrachtet.

Grundlagen des State Design Patterns

Mit dem State Design Pattern kann der Zustand von Objekten modelliert werden. Dazu werden aus einer als Context bezeichneten Klasse die zustandsabhängigen Teile in einzelne sogenannte State-Klassen ausgelagert

Wie in der untenstehenden Grafik zu sehen ist, implementieren alle State-Klassen ein gemeinsames State Interface.

State-Klassen und State Interface

Abbildung 1: State-Klassen und State Interface

Der Context hat eine Referenz auf dieses Interface. Das ist der aktuelle Zustand des Contexts. Er implementiert ebenfalls das State-Interface und leitet alle Aufrufe an seinen aktuellen State weiter.

Um Zustandswechsel zu ermöglichen, erhält der Context einen Setter für den aktuellen State und wird den konkreten State Implementierungen per Constructor injiziert. Jeder State bestimmt also seine Folgezustände, indem er den Setter auf dem Context aufruft.

Durch das Design Pattern werden Entscheidungsstrukturen wie if-else oder switch-case in der Context-Klasse durch polymorphe Strukturen ersetzt. Das macht die einzelnen Klassen kleiner, einfacher zu verstehen und zu testen. Ferner kann das System leicht um weitere Zustände erweitert werden, ohne dass dabei der Context selbst angepasst werden muss.

Anwendungsbeispiel in Android

Seit Android 6.0 werden bestimmte Berechtigungen (im Folgenden Permissions genannt) vom Benutzer erst während der Nutzung angefordert. Die App sollte also unabhängig davon, ob die Permission erteilt wurde oder nicht, funktionsfähig sein.

Eine dieser speziellen, als gefährlich eingestuften Permissions ist der Zugriff auf den aktuellen Standort des Gerätes per GPS. Wenn man nun also eine Suche implementieren will, welche einem z. B. alle Parkplätze in der Nähe zeigt, dann muss man den Benutzer nach der Permission fragen, um auf seinen Standort zugreifen zu können.

Abhängig davon, ob der Benutzer die Permission erteilt oder nicht, muss also die Suche ausgeführt werden. Der einfachste Ansatz hierfür ist in der LocationSearch Klasse ein boolean Flag zu definieren, welches abhängig von der Nutzerauswahl gesetzt wird.

Beachtet werden muss jedoch, dass der Nutzer zusätzlich die Möglichkeit hat, das GPS in den Einstellungen seines Android Gerätes zu deaktivieren. Um dies abzubilden, würde die LocationSearch Klasse also ein weiteres Flag benötigen.

Diese Implementierung führt dazu, dass an vielen Stellen in der LocationSearch Klasse abhängig von den beiden Flags anderer Code ausgeführt wird. Das sorgt dafür, dass die LocationSearch Klasse relativ groß und unübersichtlich wird. Die Wartbarkeit ist gering, der Code ist schwer an neue Anforderungen anzupassen und eine hohe Testabdeckung für diese Klasse zu erreichen, ist relativ kompliziert und aufwendig.

Doch wie kann nun das State Design Pattern eingesetzt werden, um dies zu vermeiden? Zuerst müssen alle denkbaren Zustände erfasst werden. Dazu werden GPS- und Permission-Zustand getrennt voneinander betrachtet, wie in der nachfolgenden Grafik dargestellt.

GPS- und Permission-Zustand getrennt

Abbildung 2: GPS- und Permission-Zustand getrennt

Um das Pattern anwenden zu können, müssen nun die beiden getrennten Zustände kombiniert werden. Dabei ergeben sich folgende Zustände:

Nun wird untersucht, welche Zustandswechsel (im Folgenden Transaktionen genannt) möglich sind. Diese sind nachfolgend grafisch dargestellt.

GPS- und Permission-Zustand kombiniert

Abbildung 3: GPS- und Permission-Zustand kombiniert

Das Diagramm zeigt die einzelnen Zustände und die möglichen Transaktionen. In diesem Beispiel ist es möglich das GPS an- und auszuschalten. Weiterhin besteht die Möglichkeit, die Permission zur Nutzung des GPS zu erteilen oder zu entziehen. Diese vier Transaktionen werden als Methoden in unser State Interface aufgenommen. Transaktionen, die für einen Speziellen State keine Handlung erfordern, werden einfach leer implementiert. Also der State PermissionGrantedGPSoff implementiert die Methoden off und permissionGranted zum Beispiel leer.

Die vom Zustand abhängige Logik kann nun in die entsprechenden State Klassen verschoben werden. Dadurch entstehen kleinere Klassen, die leichter zu überblicken und zu testen sind. Das komplette Klassendiagramm zum Beispiel ist in Abbildung 4 zu sehen.

Diagramm aller Klassen

Abbildung 4: Diagramm aller Klassen

Bildnachweis:

  • iStock: Zulman

Weitere Artikel aus unserem Blog