Patterns in der Softwarearchitektur: Das Schichtenmuster
(Bild: B.Forenius/shutterstock.com)
Das Schichtenmuster unterteilt eine Aufgabe in horizontale Schichten. Jede Schicht erbringt einen Dienst fĂŒr die höhere Schicht.
Patterns sind eine wichtige Abstraktion in der modernen Softwareentwicklung und Softwarearchitektur. Sie bieten eine klar definierte Terminologie, eine saubere Dokumentation und das Lernen von den Besten. Das Schichtenmuster unterteilt eine Aufgabe in horizontale Schichten. Jede Schicht hat eine bestimmte Verantwortung und erbringt einen Dienst fĂŒr die höhere Schicht.
Das Schichtenmuster oder die Schichtenarchitektur ist ein Architekturmuster, das laut dem Buch "Pattern-Oriented Software Architecture, Volume 1 [1]" hilft, Struktur in das Chaos zu bringen.
Auch bekannt als
- N-Tier-Architekturmuster
Zweck
- GroĂe Systeme, die zerlegt werden mĂŒssen
Problem
- Ein System, das Operationen auf verschiedenen Ebenen durchfĂŒhrt,
- höhere Ebenen nutzen niedrigere Ebenen
Lösung
- Strukturiere das System in Schichten,
- die Dienste einer höheren Ebene basieren auf den Diensten der unteren Ebenen.
Struktur
(Bild:Â Chunte7, CC BY-SA 3.0, via Wikimedia Commons)
Client
- Greift auf die oberste Ebene zu
Layer J
- kapselt die spezifische Rolle und Verantwortung des
Layer J, - bietet seine Dienste mithilfe des
Layer J-1an und - kann nur auf
Layer J-1zugreifen.
Obwohl es nicht festgelegt ist, bestehen die meisten Schichtenarchitekturen aus drei oder vier Schichten. Jede Schicht ist unabhĂ€ngig von den anderen. In der reinen Version kann eine Schicht nur auf die darunter liegende zugreifen. Eine Schicht kann nicht auf ihre obere zugreifen, da dies zusĂ€tzliche AbhĂ€ngigkeiten schaffen wĂŒrde und die Kontrollstruktur verkompliziert. AuĂerdem kann eine Schicht, die von einer höheren abhĂ€ngt, nicht ohne Weiteres in einer anderen Anwendung verwendet werden. Eine Schicht stellt ihre Funktionen oft durch die Implementierung des Fassaden-Musters [2] bereit. Das Fassaden-Muster bietet eine vereinfachte Schnittstelle zu einem komplexen System.
Beispiele
Das Schichtenmuster wird seit den AnfÀngen der Softwareentwicklung hÀufig verwendet. Dementsprechend gibt es viele AnwendungsfÀlle:
OSI-Modell und TCP/IP-Modell
The Open Systems Interconnection model (OSI model) is a conceptual model that 'provides a common basis for the coordination of [ISO] standards development for the purpose of systems interconnection'.[2] In the OSI reference model, the communications between a computing system are split into seven different abstraction layers: Physical, Data Link, Network, Transport, Session, Presentation, and Application. (https://en.wikipedia.org/wiki/OSI_model [3])
Ăhnliches gilt fĂŒr das vereinfachte TCP/IP-Modell: The Internet protocol suite, commonly known as TCP/IP, is a framework for organizing the set of communication protocols used in the Internet and similar computer networks according to functional criteria. The foundational protocols in the suite are the Transmission Control Protocol (TCP), the User Datagram Protocol (UDP), and the Internet Protocol (IP). (https://en.wikipedia.org/wiki/Internet_protocol_suite [4])
Embedded-Systeme
Wer Software fĂŒr eingebettete Systeme entwickelt, verwendet typischerweise in C++ verschiedene Abstraktionsebenen.
- Man beginnt normalerweise mit dem Board Support Package [5] (BSP), das Board-spezifische Konfigurationen wie Boot-Firmware und GerÀtetreiber enthÀlt, damit das eingebettete Betriebssystem funktionieren kann.
- Der Hardware Abstraction Layer [6] (HAL) befindet sich ĂŒber dem BSP. Es handelt sich dabei um eine Abstraktionsschicht zwischen der Hardware und der Software, die auf dem eingebetteten System lĂ€uft. Sie hat die Aufgabe, Unterschiede in der Hardware vor dem Betriebssystem zu verbergen.
Erweitern/Einbetten von Python in C/C++
Das Erweitern von Python in C/C++ besteht aus den folgenden Schritten:
- Konvertieren der Werte von Python nach C/C++,
- verwenden der konvertierten Werte, um die C/C++-FunktionalitĂ€t auszufĂŒhren und
- konvertieren der Ergebnisse von C/C++ nach Python.
Das Einbetten macht das Gleiche in umgekehrter Reihenfolge. Wie geht es auf der Python- und der C-Schicht weiter? Hier ist die vereinfachte Strategie.
Alle Python-Datentypen wie int erben von object.
Das C-Pendant zum Datentyp object ist das C struct PyObject. C ist nicht objektorientiert. PyObject ist eine Art Ausgangspunkt fĂŒr den Python-Objektspeicher. Die Implementierung findet sich auf GitHub: object.c [7]. PyObject hat im Wesentlichen einen ReferenzzĂ€hler und einen Zeiger auf den entsprechenden Typ.
Wenn man eine Methode fĂŒr einen Python-Typ aufruft, geht dieser Aufruf an die C-Struktur PyObject, die in object.c definiert ist. In object.c bestimmt die C-Funktion Py_TYPE den Typ des Objekts und ruft die entsprechende Funktion auf der C-Schicht auf. Das heiĂt, wenn die entsprechende Methode auf dem abgeleiteten Typ implementiert ist, wird diese aufgerufen. Ist dies nicht der Fall, wird die Standardimplementierung von PyObject aufgerufen, falls dies möglich ist.
Vor- und Nachteile
Vorteile
- Ersetzen von Schichten
Jede Schicht hat eine bestimmte Rolle und bestimmte Aufgaben. Sie bietet ihre Dienste fĂŒr die höhere Schicht ĂŒber eine Schnittstelle an. Die höhere Schicht hĂ€ngt nur von der Schnittstelle der unteren Schicht ab. Folglich kann die untere Schicht leicht ersetzt werden.
- Testbarkeit
Jede Schicht hat ihre Dienste gekapselt. Das macht es einfach, die FunktionalitĂ€t jeder Schicht zu testen. Innerhalb der Schichten mĂŒssen feinere Tests wie Unit-Tests durchgefĂŒhrt werden.
- Entwicklung
Dank der Trennung der verschiedenen Schichten (separation of concern [8]), kann jede Schicht isoliert implementiert werden. ZunÀchst muss die Schnittstelle zwischen den Schichten definiert werden.
Nachteile
- GranularitÀt der Schichten
Es kann eine Herausforderung sein, die richtige GranularitĂ€t der Schichten zu finden. Zu viele Layer können zu Schichten fĂŒhren, die nur eine minimale Verantwortung haben. AuĂerdem kann die Architektur schwer zu verstehen sein. Zu wenige Layer machen es ziemlich kompliziert, Schichten zu ersetzen, sie zu testen und isoliert zu entwickeln.
- Performanz
Ein Clientaufruf löst eine Reihe von Aufrufen aus, die in der untersten Schicht enden. Diese Abfolge von Aufrufen kann sich auf die Performanz der Anwendung negativ auswirken. Das gilt vor allem, wenn die Schichten remote sind.
Wie geht's weiter?
Das Pipes-and-Filters-Muster ist ziemlich praktisch, wenn man ein System hat, das Daten in mehreren Schritten verarbeitet, und jeder Schritt unabhĂ€ngig entwickelt werden soll. DarĂŒber werde ich in meinem nĂ€chsten Artikel schreiben. (rme [9])
URL dieses Artikels:
https://www.heise.de/-7941983
Links in diesem Artikel:
[1] https://en.wikipedia.org/wiki/Pattern-Oriented_Software_Architecture
[2] https://www.grimm-jaud.de/index.php/blog/patterns-in-der-softwareentwicklung-das-strukturpattern-fassade
[3] https://en.wikipedia.org/wiki/OSI_model
[4] https://en.wikipedia.org/wiki/Internet_protocol_suite
[5] https://en.wikipedia.org/wiki/Board_support_package
[6] https://en.wikipedia.org/wiki/Hardware_abstraction
[7] https://github.com/python/cpython/blob/d93605de7232da5e6a182fd1d5c220639e900159/Objects/object.c
[8] https://en.wikipedia.org/wiki/Separation_of_concerns
[9] mailto:rme@ix.de
Copyright © 2023 Heise Medien