Python-Entwurfsmuster

Überblick

Die moderne Softwareentwicklung muss komplexe Geschäftsanforderungen erfüllen. Es muss auch Faktoren wie zukünftige Erweiterbarkeit und Wartbarkeit berücksichtigen. Ein gutes Design eines Softwaresystems ist entscheidend, um diese Ziele zu erreichen. Entwurfsmuster spielen in solchen Systemen eine wichtige Rolle.

Betrachten wir zum Verständnis des Entwurfsmusters das folgende Beispiel:

  • Das Design jedes Autos folgt einem grundlegenden Designmuster, vier Rädern, Lenkrad, dem Kernantriebssystem wie Gaspedal-Bremskupplung usw.

Also, alle Dinge, die wiederholt gebaut / produziert werden, müssen unweigerlich einem Muster in ihrem Design folgen. Es sind Autos, Fahrräder, Pizza, Geldautomaten, was auch immer ... sogar Ihr Schlafsofa.

Entwürfe, die fast zur Standardmethode für die Codierung einer Logik / eines Mechanismus / einer Technik in Software geworden sind, werden daher als Software-Entwurfsmuster bezeichnet oder untersucht.

Warum ist Design Pattern wichtig?

Die Verwendung von Entwurfsmustern bietet folgende Vorteile:

  • Hilft Ihnen, häufig auftretende Designprobleme durch einen bewährten Ansatz zu lösen.

  • Keine Mehrdeutigkeit im Verständnis, da sie gut dokumentiert sind.

  • Reduzieren Sie die Gesamtentwicklungszeit.

  • Hilft Ihnen, mit zukünftigen Erweiterungen und Änderungen einfacher als sonst umzugehen.

  • Kann Fehler im System reduzieren, da sie bewährte Lösungen für häufig auftretende Probleme sind.

Klassifizierung von Entwurfsmustern

Die GoF-Entwurfsmuster (Gang of Four) werden in drei Kategorien eingeteilt, nämlich Kreation, Struktur und Verhalten.

Schöpfungsmuster

Kreationsentwurfsmuster trennen die Objekterstellungslogik vom Rest des Systems. Anstatt dass Sie Objekte erstellen, erstellen Kreationsmuster diese für Sie. Die Erstellungsmuster umfassen Abstract Factory, Builder, Factory Method, Prototype und Singleton.

Erstellungsmuster werden in Python aufgrund der dynamischen Natur der Sprache nicht häufig verwendet. Auch die Sprache selbst bietet uns die Flexibilität, die wir benötigen, um auf ausreichend elegante Weise zu schaffen. Wir müssen selten etwas darüber implementieren, wie Singleton oder Factory.

Diese Muster bieten auch eine Möglichkeit, Objekte zu erstellen, während die Erstellungslogik ausgeblendet wird, anstatt Objekte direkt mit einem neuen Operator zu instanziieren.

Strukturmuster

Anstatt von vorne zu beginnen, müssen Sie manchmal größere Strukturen mithilfe einer vorhandenen Gruppe von Klassen erstellen. Hier verwenden strukturelle Klassenmuster die Vererbung, um eine neue Struktur zu erstellen. Strukturelle Objektmuster verwenden Komposition / Aggregation, um eine neue Funktionalität zu erhalten. Adapter, Brücke, Verbundwerkstoff, Dekorateur, Fassade, Fliegengewicht und Proxy sind Strukturmuster. Sie bieten die besten Möglichkeiten zum Organisieren der Klassenhierarchie.

Verhaltensmuster

Verhaltensmuster bieten die besten Möglichkeiten für die Kommunikation zwischen Objekten. Muster, die unter diese Kategorien fallen, sind: Besucher, Verantwortungskette, Befehl, Dolmetscher, Iterator, Vermittler, Andenken, Beobachter, Staat, Strategie und Vorlagenmethode sind Verhaltensmuster.

Da sie das Verhalten eines Systems darstellen, werden sie allgemein zur Beschreibung der Funktionalität von Softwaresystemen verwendet.

Häufig verwendete Designmuster

Singleton

Es ist eines der umstrittensten und bekanntesten aller Designmuster. Es wird in übermäßig objektorientierten Sprachen verwendet und ist ein wesentlicher Bestandteil der traditionellen objektorientierten Programmierung.

Das Singleton-Muster wird verwendet für:

  • Wenn die Protokollierung implementiert werden muss. Die Logger-Instanz wird von allen Komponenten des Systems gemeinsam genutzt.

  • Die Konfigurationsdateien verwenden dies, da der Informationscache von allen verschiedenen Komponenten im System verwaltet und gemeinsam genutzt werden muss.

  • Verwalten einer Verbindung zu einer Datenbank.

Hier ist das UML-Diagramm,

class Logger(object):
   def __new__(cls, *args, **kwargs):
      if not hasattr(cls, '_logger'):
      cls._logger = super(Logger, cls).__new__(cls, *args, **kwargs)
return cls._logger

In diesem Beispiel ist Logger ein Singleton.

Wenn __new__ aufgerufen wird, wird normalerweise eine neue Instanz dieser Klasse erstellt. Wenn wir es überschreiben, prüfen wir zuerst, ob unsere Singleton-Instanz erstellt wurde oder nicht. Wenn nicht, erstellen wir es mit einem Super-Aufruf. Wenn wir also den Konstruktor in Logger aufrufen, erhalten wir immer genau dieselbe Instanz.

>>>
>>> obj1 = Logger()
>>> obj2 = Logger()
>>> obj1 == obj2
True
>>>
>>> obj1
<__main__.Logger object at 0x03224090>
>>> obj2
<__main__.Logger object at 0x03224090>