Freigeben über


Teil 2: Architektur

Ein wichtiger Grundsatz beim Erstellen plattformübergreifender Apps besteht darin, eine Architektur zu erstellen, die sich für eine Maximierung der plattformübergreifenden Codefreigabe eignet. Die Einhaltung der folgenden Prinzipien der objektorientierten Programmierung hilft beim Erstellen einer gut strukturierten Anwendung:

  • Kapselung : Stellen Sie sicher, dass Klassen und sogar Architekturebenen nur eine minimale API verfügbar machen, die die erforderlichen Funktionen ausführt und die Implementierungsdetails ausblendet. Auf Klassenebene bedeutet dies, dass Sich Objekte als "Blackboxen" verhalten und dass der Verbrauch von Code nicht wissen muss, wie sie ihre Aufgaben ausführen. Auf Architekturebene bedeutet dies die Implementierung von Mustern wie "Façade", die eine vereinfachte API fördern, die komplexere Interaktionen im Auftrag des Codes in abstrakteren Schichten orchestriert. Dies bedeutet, dass der Ui-Code (z. B.) nur für die Anzeige von Bildschirmen und die Annahme von Benutzereingaben verantwortlich sein sollte. und nie direkt mit der Datenbank interagieren. Ebenso sollte der Datenzugriffscode nur lesen und in die Datenbank schreiben, aber nie direkt mit Schaltflächen oder Bezeichnungen interagieren.
  • Trennung von Zuständigkeiten : Stellen Sie sicher, dass jede Komponente (sowohl auf Architektur- als auch auf Klassenebene) einen klaren und klar definierten Zweck hat. Jede Komponente sollte nur ihre definierten Aufgaben ausführen und diese Funktionalität über eine API verfügbar machen, auf die die anderen Klassen zugreifen können, die sie verwenden müssen.
  • Polymorphismus : Die Programmierung in einer Schnittstelle (oder abstrakten Klasse), die mehrere Implementierungen unterstützt, bedeutet, dass Kerncode plattformübergreifend geschrieben und freigegeben werden kann, während weiterhin mit plattformspezifischen Features interagiert wird.

Das natürliche Ergebnis ist eine Anwendung, die nach realen oder abstrakten Entitäten mit separaten logischen Ebenen modelliert ist. Durch die Aufteilung von Code in Ebenen können Anwendungen einfacher verstanden, getestet und verwaltet werden. Es wird empfohlen, den Code in jeder Schicht physisch getrennt (entweder in Verzeichnissen oder sogar separate Projekte für sehr große Anwendungen) sowie logisch getrennt (mit Namespaces) zu trennen.

Typische Anwendungsebenen

In diesem Dokument und in den Fallstudien beziehen wir uns auf die folgenden sechs Anwendungsebenen:

  • Datenschicht : Nichtflüchtige Datenpersistenz, die wahrscheinlich eine SQLite-Datenbank ist, aber mit XML-Dateien oder einem anderen geeigneten Mechanismus implementiert werden kann.
  • Datenzugriffsebene : Wrapper um die Datenschicht, die den CruD-Zugriff (Create, Read, Update, Delete) auf die Daten ermöglicht, ohne dem Aufrufer Implementierungsdetails offenzulegen. Beispielsweise kann die DAL SQL-Anweisungen enthalten, um die Daten abzufragen oder zu aktualisieren, aber der verweisende Code muss dies nicht wissen.
  • Business Layer – (manchmal auch als Business Logic Layer oder BLL bezeichnet) enthält Geschäftsentitätsdefinitionen (das Modell) und Geschäftslogik. Muster "Candidate for Business Façade".
  • Dienstzugriffsebene : Wird für den Zugriff auf Dienste in der Cloud verwendet: von komplexen Webdiensten (REST, JSON, WCF) bis hin zum einfachen Abrufen von Daten und Bildern von Remoteservern. Kapselt das Netzwerkverhalten und stellt eine einfache API bereit, die von den Anwendungs- und UI-Ebenen genutzt werden kann.
  • Anwendungsschicht : Code, der in der Regel plattformspezifisch ist (im Allgemeinen nicht plattformübergreifend freigegeben) oder Code, der für die Anwendung spezifisch ist (im Allgemeinen nicht wiederverwendbar). Ein guter Test, ob Code in der Anwendungsschicht im Vergleich zur UI-Ebene platziert werden soll, ist (a) um zu bestimmen, ob die Klasse über tatsächliche Anzeigesteuerelemente verfügt, oder (b) ob sie zwischen mehreren Bildschirmen oder Geräten (z. B. iPhone und iPad) freigegeben werden kann.
  • Benutzeroberflächenebene (UI) – Die benutzerseitige Ebene enthält Bildschirme, Widgets und die Controller, die sie verwalten.

Eine Anwendung enthält möglicherweise nicht unbedingt alle Ebenen. Beispielsweise wäre die Dienstzugriffsebene in einer Anwendung, die nicht auf Netzwerkressourcen zugreift, nicht vorhanden. Eine sehr einfache Anwendung kann die Datenschicht und die Datenzugriffsebene zusammenführen, da die Vorgänge äußerst einfach sind.

Allgemeine Muster für mobile Software

Muster sind eine etablierte Möglichkeit, wiederkehrende Lösungen für häufige Probleme zu erfassen. Es gibt einige wichtige Muster, die beim Erstellen von verwaltbaren/verständlichen mobilen Anwendungen hilfreich sind.

  • Model, View, ViewModel (MVVM): Das Model-ViewModel-Muster ist bei Frameworks beliebt, die Datenbindung unterstützen, z. B. Xamarin.Forms. Es wurde durch XAML-fähige SDKs wie Windows Presentation Foundation (WPF) und Silverlight populär gemacht, wobei das ViewModel über Datenbindung und Befehle als Wechsel zwischen den Daten (Modell) und der Benutzeroberfläche (Ansicht) fungiert.
  • Model, View, Controller (MVC) – Ein häufiges und häufig falsch verstandenes Muster, MVC wird am häufigsten beim Erstellen von Benutzeroberflächen verwendet und sorgt für eine Trennung zwischen der tatsächlichen Definition eines UI-Bildschirms (Ansicht), der Engine dahinter, die die Interaktion verarbeitet (Controller), und den Daten, die sie auffüllen (Modell). Das Modell ist eigentlich ein völlig optionales Stück und daher liegt der Kern des Verständnisses dieses Musters in der Ansicht und dem Controller. MVC ist ein beliebter Ansatz für iOS-Anwendungen.
  • Business Façade – AKA Manager Pattern, bietet einen vereinfachten Einstiegspunkt für komplexe Arbeiten. In einer Aufgabennachverfolgungsanwendung verfügen Sie beispielsweise über eine TaskManager Klasse mit Methoden wie GetAllTasks() , GetTask(taskID) , , SaveTask (task) usw. Die TaskManager -Klasse stellt eine Fassade für das innere Funktionieren des tatsächlichen Speicherns/Abrufens von Aufgabenobjekten bereit.
  • Singleton – Das Singleton-Muster bietet eine Möglichkeit, wie nur eine einzelne instance eines bestimmten Objekts jemals vorhanden sein kann. Wenn Sie beispielsweise SQLite in mobilen Anwendungen verwenden, möchten Sie immer nur eine instance der Datenbank. Die Verwendung des Singleton-Musters ist eine einfache Möglichkeit, dies sicherzustellen.
  • Anbieter : Ein von Microsoft geprägtes Muster (wohl ähnlich wie Strategie oder grundlegende Abhängigkeitsinjektion), um die Wiederverwendung von Code in Silverlight-, WPF- und WinForms-Anwendungen zu fördern. Freigegebener Code kann für eine Schnittstelle oder abstrakte Klasse geschrieben werden, und plattformspezifische konkrete Implementierungen werden geschrieben und übergeben, wenn der Code verwendet wird.
  • Asynchron: Das Asynchrone Muster ist nicht mit der Asynchronen Schlüsselwort (keyword) zu verwechseln. Das Asynchrone Muster wird verwendet, wenn lang andauernde Arbeiten ausgeführt werden müssen, ohne die Benutzeroberfläche oder die aktuelle Verarbeitung aufzuhalten. In seiner einfachsten Form beschreibt das Asynchrone Muster einfach, dass Aufgaben mit langer Ausführungsdauer in einem anderen Thread (oder einer ähnlichen Threadabstraktion wie einer Aufgabe) gestartet werden sollten, während der aktuelle Thread weiterhin verarbeitet und auf eine Antwort aus dem Hintergrundprozess lauscht und dann die Benutzeroberfläche aktualisiert, wenn Daten und oder der Zustand zurückgegeben werden.

Jedes der Muster wird ausführlicher untersucht, da ihre praktische Verwendung in den Fallstudien veranschaulicht wird. Wikipedia hat ausführlichere Beschreibungen der Muster MVVM, MVC, Facade, Singleton, Strategie und Anbieter (und von Entwurfsmustern im Allgemeinen).