Soll ich beim Schreiben von objektorientiertem Code immer einem Entwurfsmuster folgen?

37

Gibt es ein denkbares Entwurfsmuster für ein objektorientiertes Programm? Ich frage dies, weil ich vor kurzem eine Implementierung einer DoorKlasse mit a gesehen habe Lock. Es war Teil eines Tests und die Antwort besagte, dass der Code dem Null-Objektmuster folgt:

class Lock
{
public:
    virtual void close() = 0;
    virtual void open() = 0;
    virtual bool is_open() const = 0;
    virtual ~Lock() { }
};

class DummyLock
    : public Lock
{
private:
    DummyLock();
    DummyLock(const DummyLock&) = delete;
    DummyLock& operator=(const DummyLock&) = delete;

private:
    void close() { }
    void open() { }
    bool is_open() const { return true; }

public:
    static DummyLock m_instance;
};

class Door
{
public:
    Door() : m_lock(DummyLock::m_instance) { }
    Door(Lock &lock) : m_lock(lock) { }

public:
    Lock& get_lock() const { return m_lock; }

private:
    Lock &m_lock;
};

Das ließ mich denken: Dieser Code folgt einem guten Entwurfsmuster, obwohl die Beschreibung so einfach ist (diese Klasse entwirft eine Türklasse mit einem Schloss). Wenn ich also komplexeren Code schreibe, sollte es immer ein Entwurfsmuster geben, das ich habe folge ich?

user2030677
quelle
51
Glaubst du, du könntest ganz in Redewendungen sprechen? Nein? Dann sollten Sie Ihre Programme nicht durch Zusammenfügen von Entwurfsmustern erstellen.
Kilian Foth
4
In Ihrem Beispiel wird das Null-Objektmuster nur für akademische Zwecke hinzugefügt. Es führt kein "gutes Design" in diesen Code ein.
Doc Brown
4
@ Djechlin: Mit anderen Worten, verwenden Sie das "Zwei-Wort" -Design-Muster :)
Michael Shaw
11
Das Problem ist, dass zu viele Leute glauben, Designmuster seien ein Ersatz für Gedanken und ein Ersatz für Erfahrungen (was eine gewisse Menge an Versuch und Irrtum impliziert). Sie können kein Buch voller Designmuster nehmen und wie Tinker Toys zusammenstellen, um eine Anwendung mit nicht-trivialer Größe, Komplexität und anständiger Qualität zu erstellen. Selbst erfahrene Programmierer müssen oft zwei oder drei Designs ausprobieren, bevor sie eines finden, das funktioniert.
Daniel R Hicks

Antworten:

143

Sollte es immer ein Designmuster geben, dem ich folge?

Lieber Gott NEIN!

Ich meine, Sie können weitermachen und sagen, dass jeder Zufallscode einem zufälligen XYZ-Muster folgt, aber das ist nicht nützlicher, als dass ich behaupte, der König meines Computerstuhls zu sein. Niemand weiß wirklich, was das bedeutet, und selbst diejenigen, die dies tun, werden meinen Anspruch nicht genau respektieren.

Entwurfsmuster sind ein Kommunikationswerkzeug, mit dem Programmierer anderen Programmierern mitteilen können, was getan wurde oder was getan werden sollte, ohne dass sie sich ein wenig wiederholen müssen. Und da es sich um Dinge handelt, die häufig vorkommen, sind sie nützliche Konzepte für Programmierer, um zu lernen, "hey, es scheint immer so, als würde XYZ entstehen, weil es gut / nützlich ist".

Sie ersetzen nicht die Notwendigkeit, dass Sie selbst nachdenken, die Muster für das vor Ihnen liegende einzigartige Problem anpassen oder alle unvermeidlichen Dinge erledigen, die nicht in schöne Eimer passen.

Telastyn
quelle
5
Ihr erster Absatz ist Teil dessen, wie ich darauf antworten würde. Etwas wird zu einem Muster, wenn es wiederholt wird. Wenn es so oft wiederholt wird, dass eine Kommunikation erforderlich ist, handelt es sich um ein Muster , das von einem Namen profitiert. Einige argumentieren sogar, dass ein Muster nur entsteht, weil eine Abstraktion fehlt. Das Streben nach Mustern ist der Weg zur Schande als Mitglied des gepriesenen Frachtkults.
Magus
11
@Cerad: Sicher, solange du versprichst, nicht auch Gottesklassen zu schreiben!
Yatima2975
9
John Doe - Technischer Ingenieur, Affe mit generischem Code und König seines Computerstuhls
hjk
1
Ein Entwurf sollte gegebenenfalls Muster verwenden und Klassen sollten als solche benannt werden. Sie sind ein wichtiges Werkzeug. Angst vor the_cult(tm) ist genauso gefährlich.
Gusdor
25
Gute Antwort! Mein einziger Kritikpunkt ist, dass das "Lieber Gott NEIN!" ist nicht groß genug
Bis
37

Nein.

Das hat die Viererbande (die ursprünglich Designmuster populär gemacht hat) in ihrem Buch dazu gesagt :

"Keine Diskussion über die Verwendung von Designmustern wäre vollständig, ohne ein paar Worte darüber, wie man sie nicht verwendet. Designmuster sollten nicht wahllos angewendet werden. Oft erreichen sie Flexibilität und Variabilität, indem sie zusätzliche Indirektionsebenen einführen, was ein Design erschweren kann und / oder Sie etwas Leistung kosten. Ein Entwurfsmuster sollte nur angewendet werden, wenn die Flexibilität, die es bietet, tatsächlich benötigt wird. "

Das Beispiel, das Sie zeigen, macht eigentlich nicht viel (ich glaube nicht, dass es dazu gedacht war, ich denke, es war nur als Beispiel gedacht). An sich benötigt es kein Null-Objektmuster. Im Kontext eines größeren Programms könnte es sein.

Der falsche Ansatz geht davon aus, dass es gut sein muss, nur weil es als "Entwurfsmuster" bezeichnet wurde, und dann nach mehr Stellen Ausschau zu halten, an denen mehr Muster eingefügt werden können. Verwenden Sie diese, wenn sie zum Programm passen und tatsächlich ein Problem für Sie lösen.

Michael Shaw
quelle
7
Das Buch ist Design Patterns: Elemente wiederverwendbarer objektorientierter Software von Erich Gamma, Richard Helm, Ralph Johnson und John Vlissides.
Developerwjk
4
+1 Für das tatsächliche Zitieren der Quelle der Entwurfsmuster.
Pharap
29

Wenn ich komplexeren Code schreibe, sollte es dann immer ein Designmuster geben, dem ich folge?

Nein. Designmuster sind genau das: Muster in Beziehungen zwischen Objekten. Mit anderen Worten, Beziehungen, die häufig genug genutzt und wiederverwendet werden, dass jemand sagte: "Hey, wir scheinen das sehr oft zu tun, geben wir ihr einen Namen." Die Liste der Entwurfsmuster wurde zu Beginn von OOP nicht auf einmal festgelegt und dann von GOF ! Sie wurden entdeckt und schließlich dokumentiert und dann durch das Buch populär gemacht.

Ein großer Vorteil von Entwurfsmustern besteht jedoch darin, dass sie das Nachdenken über Softwareentwurf auf einer höheren Ebene erleichtern. Sie können sich keine Gedanken über Implementierungsdetails machen und mehr über das Gesamtbild nachdenken. In diesem Sinne befreien sie dich von den Kleinigkeiten, aber sie können dich auch auf die gleiche Weise einschränken, wie die Art, wie du dich ausdrückst, durch die Wörter, die du kennst, eingeschränkt werden kann. So kann es eine Zeit kommen , wenn es ist ein Musterentwurf für die meisten von dem, was Sie tun , nur weil die Muster , die Sie wissen , sind die Begriffe , in denen Sie denken. Halten Sie die Augen offen für Fälle, in denen Sie möglicherweise ein Muster missbrauchen und über bessere Vorgehensweisen nachdenken müssen.

Beachten Sie auch, dass Sie in der Praxis ein bestimmtes Entwurfsmuster häufig nicht so sehr implementieren, als dass Sie das Muster in einem vorhandenen Code wie einem Objektframework erkennen. Wenn Sie sich mit gängigen Entwurfsmustern auskennen, können Sie leichter lernen, wie ein Framework verwendet werden soll, da Sie die Beziehungen zwischen Klassen in Begriffen sehen können, die Sie bereits verstanden haben.

Caleb
quelle
10

Entwurfsmuster haben zwei Vorteile

  1. Sie sind für andere Entwickler leicht zu beschreiben, da sich die Leute im Allgemeinen über die Muster einig sind
  2. Sie wurden von unseren Vorgängern eher nachdenklich geschlagen, sodass ihre Stärken und Schwächen gut verstanden werden.

Die Ziele eines jeden Programms sollten sein

  1. Es klappt. Es muss tun, was auch immer das Endziel ist, oder es spielt keine Rolle, wie viele Entwurfsmuster Sie verwenden. OO-Entwurfsmuster machen es einfach, das Problem in leicht verständliche Teile zu zerlegen, damit es leichter zu beweisen ist, dass es funktioniert.
  2. Es ist leicht zu lesen. Hier sind Designmuster schön. Die OO-Probleme, die sie lösen, sind kompliziert. Wenn Sie sie auf "normale" Weise lösen, ist es für den nächsten Entwickler einfacher
  3. Es ist leicht zu züchten. Nahezu 0 moderne Programme enden dort, wo sie von allen geplant wurden. Jedes Programm wächst nach seiner Erstveröffentlichung. OO-Muster sind dafür bekannt, seltsamerweise gut zu wachsen.

Wenn alles gesagt ist, beachten Sie, dass jeder Verweis auf OO-Designmuster "sie sind einfach gut in der Arbeit." Sie sind nicht perfekt, füllen aber sehr effektiv eine Nische. Verwenden Sie sie, wenn sie arbeiten, vermeiden Sie sie, wenn sie es nicht tun.

Als Beispiel für "komplexen Code" nehmen Sie, wie Sie in Ihrer Frage erwähnt haben, eine Skriptsprache, die ich geschrieben habe. Das meiste davon ist OO mit Designmustern überall. Als ich jedoch den Müllsammler schrieb, ließ ich kurzerhand alle Täuschungen von OO fallen, weil die besonderen Dinge, die ich tun musste, besser als altmodisches Bit-Bashing modelliert waren. Es gibt kein OO-Muster in der gesamten Sache, bis es zum Schreiben von Finalisierern kam, wo OO wieder anfing, ein nützliches Modell zu sein. Ohne Pomp oder Umstände wurde der Code plötzlich wieder auf die Verwendung von OO-Techniken umgestellt.

Verwenden Sie Entwurfsmuster, wenn sie Ihr Produkt verbessern. Vermeiden Sie sie, wenn sie Ihr Produkt verschlechtern.

Cort Ammon
quelle
2
Ich denke, der letzte Satz sollte in Fettdruck oder als Zusammenfassung oben stehen.
Pharap
5

Ich werde mich dem Trend ein wenig widersetzen, weil die Antwort subtiler ist, als andere Antworten es zulassen. Jede Klasse, die Sie schreiben, sollte kein Entwurfsmuster verwenden, aber die meisten nicht trivialen Programme, die Sie schreiben, sollten dies wahrscheinlich tun.

Ein nicht-triviales Programm ohne Designmuster zeigt Folgendes an:

  • Ihr Programm ist so einzigartig, dass kein Teil des Programms mit den Problemen vergleichbar ist, mit denen Programmierer zuvor konfrontiert waren. Oder
  • Ihr Programm enthält diese allgemeinen Probleme, aber Sie haben sie auf eine bessere Art und Weise gelöst, als bisher noch niemand gedacht hat.

Beide Szenarien sind höchst unwahrscheinlich, keine Beleidigung.

Das bedeutet nicht, dass das Entwurfsmuster Ihr Entwurf bestimmen sollte, oder dass Sie eines wahllos einfügen sollten, da Sie der Meinung sind, dass es schlecht aussehen wird, wenn Sie dies nicht tun. Das falsche Designmuster ist schlimmer als keines.

Das heißt, Sie sollten einen Mangel an Designmustern in Ihrem Gesamtprogramm als Code-Geruch betrachten. Etwas, das Sie veranlasst, einen zweiten Blick darauf zu werfen und eine Neubewertung vorzunehmen, wenn Ihr Design nicht sauberer sein könnte. Wenn Sie sich zu diesem Zeitpunkt dafür entscheiden, Designmuster aus einem Programm herauszulassen, sollte dies eine bewusste, informierte Entscheidung sein, nicht ein Zufall.

Sie sagen beispielsweise nicht: "Ich muss eine Tür und ein Schloss modellieren. Welches Entwurfsmuster soll ich verwenden?" Wenn Sie es jedoch zuerst entworfen haben, ohne Designmuster zu verwenden, sollten Sie anschließend gefragt werden, ob es ein Designmuster gibt, mit dem Sie diese verwalten können.

Sieh den Unterschied? Es ist eine subtile, aber wichtige Unterscheidung.

Karl Bielefeldt
quelle
5
Es gibt viel mehr Probleme (und ihre gemeinsamen Lösungen) als Entwurfsmuster. Entwurfsmuster sind eine katalogisierte Teilmenge gängiger OO-Lösungen - nicht die Menge aller gängigen Lösungen.
Michael Shaw
1
Könnten Sie definieren, was Sie mit "nicht-trivial" meinen? Ich hatte den Eindruck, dass der Begriff "nicht-trivial" subjektiv war.
Pharap
1
Es ist subjektiv. Ich meine die Art von Programm, die Sie in einem Team bei der Arbeit schreiben würden und für das mehrere Betreuer fortlaufend benötigt werden.
Karl Bielefeldt
Wenn Sie Glück genug , um zu sehen , Ihr Problem danach. Nullschecks, klar. Sicherheitslücken? Andere heimtückische Wege, auf denen das Programm bei der Wartung kaputt geht? Probleme, die nur der nächste Ingenieur aufdecken wird? Viel glücklicher.
Djechlin
"Ich muss eine Tür und ein Schloss modellieren, wie soll die Schnittstelle aussehen? Wird die Leistung Bestandteil des Vertrags sein? Soll ich einen Dienst oder eine Bibliothek nutzen? Wie werden Ressourcen weitergegeben?" sollten alle gefragt werden, und Sie sollten Antworten haben, die grundsätzlich als Entwurfsmuster angesehen werden.
Djechlin
4

Gebrochene Frage. Lassen Sie mich eine neuartige Definition des Entwurfsmusters geben, die einen Großteil des von GoF verursachten Schadens rückgängig machen würde: Ein Entwurfsmuster ist eine gute Codierungspraxis . Das ist es.

Jedes einigermaßen komplexe Modul enthält mehrere Entwurfsmuster. Jedes Mal, wenn Sie im Cache speichern, handelt es sich wahrscheinlich um ein Fliegengewichtmuster, aber ich werde Ihren Programmiergrad nicht widerrufen, wenn Sie ihn nicht so nennen. Jedes Mal, wenn Sie einen Rückruf erhalten, befinden Sie sich in einem Ereignis- / Feuer- / Rückrufmuster. usw. Wenn Sie das Wort "statisch" haben, haben Sie einen Singleton. Wenn Sie einen statischen Konstruktor haben, haben Sie ein Factory-Muster. Wenn eine Ressource an Ihr Modul übergeben wird, verwenden Sie die Abhängigkeitsinjektion.

"Design Pattern" ist ein gebrochener Begriff, der von GoF schlecht populär gemacht wird. Es hört sich so an, als wären alle Patterns auf dem gleichen Level, oder Sie sollten den vom Arzt empfohlenen 3 bis 5 pro Klasse verwenden. Jedes Mal, wenn Sie etwas richtig machen, was jemand anderes richtig gemacht hat, ist es ein Entwurfsmuster . A for(;;)ist ein übliches Muster, das zum Beispiel zur Darstellung einer Endlosschleife verwendet wird.

Sie sollten nicht versuchen, ein paar Designmuster zu lernen. Programmierkenntnisse werden nicht durch Entwurfsmuster indiziert! Sie sollten vielmehr lernen, wie Sie guten Code schreiben, indem Sie Bücher und Blogs lesen und an Konferenzen in Ihrem Bereich teilnehmen. Wenn Sie beispielsweise bereits die Abhängigkeitsinjektion verwenden, diese jedoch nicht benannt haben, können Sie davon profitieren, immer DI oder ein IoC-Framework zu verwenden. Wenn Sie Schwierigkeiten haben, in Ereignissen und Rückrufen richtig zu programmieren, lernen Sie Haskell, damit Sie mit funktionalen Entwurfsmustern vertraut sind und es einfach wird.

Und wenn Ihre gesamte Klasse als eine große Sache liest, die jemand anderes richtig gemacht hat, warum erfinden Sie dann das Rad neu? Verwenden Sie einfach ihre Sachen.

djechlin
quelle
2
In welcher Sprache ist for(;;)idiomatisch? Das ist wahrscheinlich nicht das beste Beispiel für etwas, das jemand "richtig" gemacht hat.
Telastyn
1
@Telastyn C, C ++, Java, Javascript, C #.
Djechlin
2
Ich habe noch nie gesehen jemand es vorziehen , dass über while(true)(oder while(1)) in C, C ++, Java oder C # in meinen 20 Jahren der Programmierung.
Telastyn
1
@Telastyn stackoverflow.com/a/2611744/1339987 fwiw Ich bevorzuge zwar (true), weil es für mich lesbarer aussieht.
Djechlin
1
Ich benutze immer für (;;). Kein besonderer Grund, ich habe es wahrscheinlich irgendwo gelesen. Mir gefällt die Tatsache, dass keine Variablen oder Konstanten beteiligt sind. Wie auch immer, @Telastyn, jetzt hast du jemanden getroffen .
Ant
0

Sie sollten immer die OO-Entwurfsprinzipien befolgen (z. B. Modularität, Ausblenden von Informationen, hohe Kohäsion usw.). Entwurfsmuster sind eine relativ raffinierte Nische der OO-Entwurfsprinzipien, insbesondere wenn Sie das KISS-Prinzip berücksichtigen .

Muster sind Lösungen für häufig auftretende Designprobleme. Diese Probleme kommen von einer von zwei Stellen (oder einer Mischung aus beiden): dem Problembereich (z. B. Software zur Verwaltung der Humanressourcen in einem Unternehmen) und dem Lösungsbereich . Ein OO-Programm ist eine Instanz innerhalb des Lösungsbereichs (z. B. eine von vielen Möglichkeiten, ein OO-Programm zu entwerfen, um die Verwaltung von HR zu vereinfachen).

Es ist nicht so einfach zu wissen, wann ein Muster zu verwenden ist. Einige Muster befinden sich auf niedriger Ebene, näher an der Codierung und am Lösungsraum (z. B. Singleton, Null-Objekt, Iterator). Andere werden durch Anforderungen im Problembereich motiviert (z. B. Befehlsmuster zur Unterstützung von Rückgängig / Wiederherstellen, Strategie zur Unterstützung mehrerer Eingabe- / Ausgabedateitypen).

Viele Muster ergeben sich aus der Notwendigkeit, künftige Variationen der Software zu unterstützen. Wenn Sie diese Variationen nie vornehmen müssen, kann ein Muster überzeichnet sein. Ein Beispiel wäre die Verwendung des Adaptermusters für die Arbeit mit der vorhandenen externen HR-Datenbank. Sie entscheiden sich für den Einsatz von Adapter, da die aktuelle Datenbank mit Oracle zusammenarbeitet und Sie möglicherweise NoSQL in Zukunft unterstützen möchten. Wenn NoSQL niemals in Ihre Organisation kommt, kann dieser Adaptercode sehr wohl unbrauchbar sein. Siehe YAGNI . Die Unterstützung für Variationen, die niemals auftreten, ist die falsche Verwendung eines Entwurfsmusters.

Fuhrmanator
quelle
0

Muster sind übliche Lösungen für häufig auftretende Probleme. Wir folgen immer einigen Mustern, die Muster von GoF sprechen die am häufigsten vorkommenden an. Das, um ein gemeinsames Verständnis und einen gemeinsamen Ansatz zu haben, die den Software-Ingenieuren bekannt sind.

Das heißt, meine Antwort ist nein, aber ja, Sie folgen immer einem eigenen Muster. Wie die GoF zu Recht sagt,

Das Muster einer Person ist der primitive Baustein einer anderen Person.

Großartiges Zitat.

Syed Priom
quelle
dies scheint nicht zu bieten alles wesentliche über gemacht Punkte und erläuterte vor 7 Antworten
gnat
Fein. Beachten Sie, dass ich einen allgemeinen Punkt gemacht habe ... er gilt für Entwurfsmuster als theoretische Diskussion.
Syed Priom
„Diese Seite ist über die Antworten bekommen Es ist kein Diskussionsforum ....“ ( Tour )
gnat
Ich habe die Frage beantwortet. Vielen Dank. Dieses Gespräch endet hier.
Syed Priom
@gnat es ist eine Menge prägnanter.
Djechlin
0

Wenn ich Code schreibe, plane ich nicht, so viele Entwurfsmuster wie möglich absichtlich zu verwenden. Aber ich denke, wenn ich unbewusst ein Codierungsproblem bekomme, scheint eines der Designmuster zu passen, und ich benutze es einfach. Und manchmal passt nichts. Was mir wichtiger ist, ist das Schreiben von Code, der die Arbeit erledigt und einfach zu warten und zu erweitern ist.

Hier finden Sie einen Artikel zum Anwenden von OOD-Prinzipien mithilfe von Entwurfsmustern sowie Codebeispiele (in C ++). Es zeigt, wie und wann einige der Entwurfsmuster angewendet werden müssen, um sauberen Code zu schreiben.

Rosenwasser
quelle
2
Dieser Artikel wurde erst gestern geschrieben; Sind Sie überhaupt mit dem Blog verbunden? Wenn ja, geben Sie bitte diese Zugehörigkeit bekannt .
Martijn Pieters