Lassen Sie mich zunächst sagen, dass mir die Konzepte der Abstraktion und der Abhängigkeitsinjektion bekannt sind. Ich muss meine Augen hier nicht öffnen.
Nun, die meisten von uns sagen (zu) oft, ohne wirklich zu verstehen: "Benutze keine globalen Variablen" oder "Singletons sind böse, weil sie global sind". Aber was wirklich ist so schlecht über den ominösen globalen Zustand?
Angenommen, ich benötige eine globale Konfiguration für meine Anwendung, z. B. Systemordnerpfade oder anwendungsweite Datenbankanmeldeinformationen.
In diesem Fall sehe ich keine andere gute Lösung als die Bereitstellung dieser Einstellungen in einem globalen Bereich, der normalerweise für die gesamte Anwendung verfügbar ist.
Ich weiß , dass es schlecht ist zu missbrauchen , aber ist der globale Raum wirklich DASS Übel? Und wenn ja, welche guten Alternativen gibt es?
quelle
Antworten:
Sehr kurz, es macht den Programmstatus unvorhersehbar.
Stellen Sie sich vor, Sie haben ein paar Objekte, die beide dieselbe globale Variable verwenden. Angenommen, Sie verwenden in keinem Modul eine Zufallsquelle, kann die Ausgabe einer bestimmten Methode vorhergesagt (und daher getestet) werden, wenn der Systemstatus bekannt ist, bevor Sie die Methode ausführen.
Wenn jedoch eine Methode in einem der Objekte einen Nebeneffekt auslöst, der den Wert des gemeinsam genutzten globalen Status ändert, wissen Sie nicht mehr, wie der Ausgangsstatus lautet, wenn Sie eine Methode im anderen Objekt ausführen. Sie können jetzt nicht mehr vorhersagen, welche Ausgabe Sie erhalten, wenn Sie die Methode ausführen, und können sie daher nicht testen.
Auf akademischer Ebene mag dies nicht sehr ernst klingen, aber die Fähigkeit, Code als Einheit zu testen, ist ein wichtiger Schritt bei der Überprüfung seiner Richtigkeit (oder zumindest seiner Eignung für den Zweck).
In der realen Welt kann dies schwerwiegende Folgen haben. Angenommen, Sie haben eine Klasse, die eine globale Datenstruktur auffüllt, und eine andere Klasse, die die Daten in dieser Datenstruktur verarbeitet, ihren Status ändert oder sie dabei zerstört. Wenn die Prozessorklasse eine Methode ausführt, bevor die Populatorklasse fertig ist, ist das Ergebnis, dass die Prozessorklasse wahrscheinlich unvollständige Daten zu verarbeiten hat und die Datenstruktur, an der die Populatorklasse gearbeitet hat, beschädigt oder zerstört werden könnte. Das Programmverhalten wird unter diesen Umständen völlig unvorhersehbar und wird wahrscheinlich zu einem epischen Verlust führen.
Darüber hinaus beeinträchtigt der globale Status die Lesbarkeit Ihres Codes. Wenn Ihr Code eine externe Abhängigkeit hat, die nicht explizit in den Code aufgenommen wurde, muss jeder, der die Pflege Ihres Codes übernimmt, danach suchen, um herauszufinden, woher er stammt.
Was Alternativen angeht, so ist es unmöglich, überhaupt keinen globalen Status zu haben, aber in der Praxis ist es normalerweise möglich, den globalen Status auf ein einzelnes Objekt zu beschränken, das alle anderen Objekte einschließt und auf das niemals unter Berufung auf die Gültigkeitsregeln verwiesen werden darf der Sprache, die Sie verwenden. Wenn ein bestimmtes Objekt einen bestimmten Zustand benötigt, sollte es explizit danach fragen, indem es als Argument an seinen Konstruktor oder durch eine Setter-Methode übergeben wird. Dies wird als Abhängigkeitsinjektion bezeichnet.
Es mag albern erscheinen, einen Status zu übergeben, auf den Sie aufgrund der Gültigkeitsregeln der von Ihnen verwendeten Sprache bereits zugreifen können, aber die Vorteile sind enorm. Wenn jemand den Code isoliert betrachtet, ist klar, welchen Status er benötigt und woher er kommt. Es hat auch enorme Vorteile in Bezug auf die Flexibilität Ihres Codemoduls und damit die Möglichkeit, es in verschiedenen Kontexten wiederzuverwenden. Wenn der Status übergeben wird und Änderungen am Status für den Codeblock lokal sind, können Sie einen beliebigen Status übergeben (sofern es sich um den richtigen Datentyp handelt) und den Code von Ihrem Code verarbeiten lassen. Code, der in diesem Stil geschrieben wurde, sieht in der Regel wie eine Sammlung lose zugeordneter Komponenten aus, die leicht ausgetauscht werden können. Dem Code eines Moduls sollte es egal sein, woher der Status kommt, nur wie er verarbeitet wird.
Es gibt viele andere Gründe, warum die Weitergabe des Staates der Nutzung des globalen Staates weit überlegen ist. Diese Antwort ist keineswegs umfassend. Sie könnten wahrscheinlich ein ganzes Buch darüber schreiben, warum der globale Zustand schlecht ist.
quelle
being able to unit test code is a major step in the process of proving its correctness (or at least fitness for purpose)
. Nein, ist es nicht. "Es ist nun zwei Jahrzehnte her, seit darauf hingewiesen wurde, dass Programmtests das Vorhandensein von Fehlern überzeugend nachweisen können, jedoch niemals deren Abwesenheit. Nachdem der Softwareentwickler diese gut publizierte Bemerkung mit Nachdruck zitiert hat, kehrt er zur Tagesordnung zurück und fährt fort seine Teststrategien zu verfeinern, genau wie der Alchemist von damals, der seine chrysokosmischen Reinigungen weiter verfeinerte. " - Djikstra, 1988. (Das sind jetzt 4,5 Jahrzehnte ...)Veränderlicher globaler Staat ist aus vielen Gründen böse:
Alternativen zum veränderlichen globalen Staat:
quelle
grep
herauszufinden, welche Funktionen den Typnamen verwenden.Übergeben Sie einfach eine Referenz an Funktionen, die sie benötigen. Es ist nicht so schwer.
quelle
Wenn Sie "Zustand" sagen, bedeutet dies normalerweise "veränderlicher Zustand". Und ein globaler veränderlicher Zustand ist völlig böse, weil dies bedeutet, dass jeder Teil des Programms jeden anderen Teil beeinflussen kann (indem er den globalen Zustand ändert).
Stellen Sie sich das Debuggen eines unbekannten Programms vor: Sie finden, dass sich die Funktion A für bestimmte Eingabeparameter auf eine bestimmte Weise verhält, aber manchmal für dieselben Parameter anders funktioniert. Sie stellen fest, dass die globale Variable x verwendet wird .
Sie suchen nach Stellen, die x ändern , und stellen fest, dass es fünf Stellen gibt, die x ändern. Nun viel Glück beim Herausfinden, in welchen Fällen Funktion A was tut ...
quelle
Sie haben sozusagen Ihre eigene Frage beantwortet. Sie sind schwierig zu handhaben, wenn sie "missbraucht" werden, können aber nützlich und [etwas] vorhersehbar sein, wenn sie richtig verwendet werden, von jemandem, der weiß, wie man sie unterdrückt. Wartung und Änderungen an / auf den Globals sind in der Regel ein Albtraum, der sich mit zunehmender Größe der Anwendung verschlimmert.
Erfahrene Programmierer, die den Unterschied zwischen Globals als einzige Option und der einfachen Lösung erkennen können, haben möglicherweise nur minimale Probleme bei der Verwendung. Die endlosen möglichen Probleme, die bei ihrer Verwendung auftreten können, erfordern jedoch den Rat, sie nicht zu verwenden.
Bearbeiten: Um zu verdeutlichen, was ich meine, sind Globals von Natur aus nicht vorhersehbar. Wie bei allem Unvorhersehbaren können Sie Schritte unternehmen, um die Unvorhersehbarkeit einzudämmen, aber es gibt immer Grenzen, was getan werden kann. Hinzu kommt der Ärger neuer Entwickler, die sich dem Projekt anschließen und sich mit relativ unbekannten Variablen auseinandersetzen müssen. Die Empfehlungen gegen die Verwendung globaler Variablen sollten verständlich sein.
quelle
Es gibt viele Probleme mit Singletons - hier sind die zwei größten Probleme in meinem Kopf.
Dies macht das Testen von Einheiten problematisch. Der globale Zustand kann von einem Test zum nächsten kontaminiert werden
Es erzwingt die "One-and-only-one" -Hard-Regel, die sich zwar unmöglich ändern kann, aber plötzlich erfüllt. Eine ganze Reihe von Utility-Code, der das global zugängliche Objekt verwendet, muss dann geändert werden.
Allerdings benötigen die meisten Systeme Big Global Objects. Hierbei handelt es sich um umfangreiche und kostenintensive Elemente (z. B. Database Connection Manager) oder um Informationen zum allgegenwärtigen Status (z. B. Sperrinformationen).
Die Alternative zu einem Singleton besteht darin, diese großen globalen Objekte beim Start zu erstellen und als Parameter an alle Klassen oder Methoden zu übergeben, die Zugriff auf dieses Objekt benötigen.
Das Problem hierbei ist, dass Sie am Ende ein großes Spiel "Pass-the-Parcel" haben. Sie haben ein Diagramm der Komponenten und ihrer Abhängigkeiten, und einige Klassen erstellen andere Klassen, und jede muss eine Reihe von Abhängigkeitskomponenten enthalten, nur weil ihre gespawnten Komponenten (oder die Komponenten der gespawnten Komponenten) sie benötigen.
Sie haben neue Wartungsprobleme. Ein Beispiel: Plötzlich benötigt Ihre "WidgetFactory" -Komponente tief im Diagramm ein Timer-Objekt, das Sie verspotten möchten. "WidgetFactory" wird jedoch von "WidgetBuilder" erstellt, das Teil von "WidgetCreationManager" ist, und Sie müssen drei Klassen haben, die über dieses Timer-Objekt Bescheid wissen, obwohl nur eine es tatsächlich verwendet. Sie möchten aufgeben und zu Singletons zurückkehren und dieses Timer-Objekt einfach global zugänglich machen.
Glücklicherweise ist dies genau das Problem, das durch ein Dependency Injection-Framework gelöst wird. Sie können dem Framework einfach mitteilen, welche Klassen es erstellen muss, und es verwendet Reflection, um das Abhängigkeitsdiagramm für Sie zu ermitteln, und erstellt jedes Objekt automatisch, wenn sie benötigt werden.
Zusammenfassend sind Singletons also schlecht, und die Alternative ist die Verwendung eines Abhängigkeitsinjektions-Frameworks.
Ich benutze zufällig Castle Windsor, aber Sie haben die Qual der Wahl. Auf dieser Seite aus dem Jahr 2008 finden Sie eine Liste der verfügbaren Frameworks.
quelle
Zunächst einmal müssten Sie Singletons verwenden, damit die Abhängigkeitsinjektion "stateful" ist. Leute, die sagen, dies sei irgendwie eine Alternative, irren sich. Menschen verwenden ständig globale Kontextobjekte ... Auch der Sitzungsstatus ist im Wesentlichen eine globale Variable. Es ist nicht immer die beste Lösung, alles durch Abhängigkeitsinjektion weiterzugeben. Ich arbeite derzeit an einer sehr großen Anwendung, die viele globale Kontextobjekte verwendet (Singletons, die über einen IoC-Container injiziert werden), und das Debuggen war noch nie ein Problem. Insbesondere bei einer ereignisgesteuerten Architektur kann es vorzuziehen sein, globale Kontextobjekte zu verwenden, anstatt Änderungen weiterzugeben. Kommt darauf an, wen du fragst.
Alles kann missbraucht werden und es hängt auch von der Art der Anwendung ab. Die Verwendung statischer Variablen zum Beispiel in einer Web-App unterscheidet sich grundlegend von einer Desktop-App. Wenn Sie globale Variablen vermeiden können, tun Sie dies, aber manchmal haben sie ihre Verwendung. Stellen Sie zumindest sicher, dass sich Ihre globalen Daten in einem klaren Kontextobjekt befinden. Was das Debuggen betrifft, kann nichts, was ein Aufrufstapel und einige Haltepunkte nicht lösen.
Ich möchte betonen, dass die blinde Verwendung globaler Variablen eine schlechte Idee ist. Funktionen sollten wiederverwendbar sein und es sollte ihnen egal sein, woher die Daten kommen - bei Bezug auf globale Variablen wird die Funktion mit einer bestimmten Dateneingabe gekoppelt. Dies ist der Grund, warum es weitergegeben werden sollte und warum die Abhängigkeitsinjektion hilfreich sein kann, obwohl es sich immer noch um einen zentralisierten Kontextspeicher handelt (über Singletons).
Übrigens ... Einige Leute denken, dass die Abhängigkeitsinjektion schlecht ist, einschließlich des Erstellers von Linq. Letztendlich wird Erfahrung Ihr bester Lehrer sein. Es gibt Zeiten, um Regeln zu befolgen und Zeiten, um sie zu brechen.
quelle
Da hier einige andere Antworten die Unterscheidung zwischen veränderlichem und unveränderlichem globalem Zustand treffen, möchte ich meinen, dass selbst unveränderliche globale Variablen / Einstellungen oft ärgerlich sind .
Betrachten Sie die Frage:
Richtig, für ein kleines Programm ist dies wahrscheinlich kein Problem, aber sobald Sie dies mit Komponenten in einem etwas größeren System tun , wird das Schreiben automatisierter Tests plötzlich schwieriger, da alle Tests (die innerhalb desselben Prozesses ablaufen) funktionieren müssen der gleiche globale Konfigurationswert.
Wenn alle Konfigurationsdaten explizit übergeben werden, lassen sich die Komponenten viel einfacher testen und Sie müssen sich keine Gedanken mehr darüber machen, wie Sie einen globalen Konfigurationswert für mehrere Tests booten, möglicherweise sogar parallel.
quelle
Zum einen können Sie genau das Problem angehen, das Sie mit Singletons haben. Was heute wie eine "globale Sache aussieht, von der ich nur eine brauche", wird sich plötzlich in etwas verwandeln, von dem Sie später mehr brauchen.
Zum Beispiel erstellen Sie heute dieses globale Konfigurationssystem, weil Sie eine globale Konfiguration für das gesamte System wünschen. Ein paar Jahre später portieren Sie auf ein anderes System und jemand sagt: "Hey, wissen Sie, das könnte besser funktionieren, wenn es eine allgemeine globale Konfiguration und eine plattformspezifische Konfiguration gäbe." Plötzlich haben Sie diese ganze Arbeit, um Ihre globalen Strukturen nicht global zu machen, so dass Sie mehrere haben können.
(Dies ist kein zufälliges Beispiel ... dies geschah mit unserem Konfigurationssystem in dem Projekt, in dem ich mich gerade befinde.)
In Anbetracht der Tatsache, dass die Kosten für die Erstellung eines nicht-globalen Objekts in der Regel gering sind, ist es dumm, dies zu tun. Sie schaffen nur zukünftige Probleme.
quelle
Das andere Problem ist merkwürdigerweise, dass sie die Skalierbarkeit einer Anwendung erschweren, weil sie nicht "global" genug sind. Der Gültigkeitsbereich einer globalen Variablen ist der Prozess.
Wenn Sie Ihre Anwendung mithilfe mehrerer Prozesse oder auf mehreren Servern skalieren möchten, ist dies nicht möglich. Zumindest erst, wenn Sie alle Globalen herausgerechnet und durch einen anderen Mechanismus ersetzt haben.
quelle
Ein veränderlicher globaler Zustand ist böse, weil es für unser Gehirn sehr schwierig ist, mehr als ein paar Parameter gleichzeitig zu berücksichtigen und herauszufinden, wie sie sich aus einer Timing-Perspektive und einer Werteperspektive kombinieren, um etwas zu bewirken.
Daher sind wir sehr schlecht darin, ein Objekt zu debuggen oder zu testen, dessen Verhalten mehr als ein paar externe Gründe hat, die während der Ausführung eines Programms geändert werden müssen. Geschweige denn, wenn wir über Dutzende dieser Objekte zusammen denken müssen.
quelle
Sprachen, die für ein sicheres und robustes Systemdesign entwickelt wurden, entfernen häufig den globalen veränderlichen Status insgesamt. (Vermutlich bedeutet dies, dass es keine globalen Objekte gibt, da unveränderliche Objekte in gewissem Sinne nicht wirklich zustandsbehaftet sind, da sie niemals einen Zustandsübergang haben.)
Joe-E ist ein Beispiel, und David Wagner erklärt die Entscheidung folgendermaßen:
Eine Möglichkeit, darüber nachzudenken, ist
Ein global veränderlicher Zustand erschwert es daher
Der globale veränderbare Zustand ähnelt der DLL-Hölle . Im Laufe der Zeit erfordern verschiedene Teile eines großen Systems ein subtil anderes Verhalten als gemeinsame Teile eines veränderlichen Zustands. Das Lösen von Inkonsistenzen zwischen DLL-Höllen und gemeinsam genutzten veränderlichen Zuständen erfordert eine umfassende Koordination zwischen verschiedenen Teams. Diese Probleme würden nicht auftreten, wenn der globale Staat von Anfang an richtig eingeschätzt worden wäre.
quelle
Globals sind nicht so schlimm. Wie in mehreren anderen Antworten angegeben, besteht das eigentliche Problem darin, dass Ihr globaler Ordnerpfad heute morgen einer von mehreren oder sogar Hunderten sein kann. Wenn Sie ein schnelles, einmaliges Programm schreiben, verwenden Sie Globals, wenn es einfacher ist. Im Allgemeinen ist es jedoch der richtige Weg, ein Vielfaches zuzulassen, auch wenn Sie nur glauben, dass Sie eines brauchen. Es ist nicht angenehm, ein großes komplexes Programm neu strukturieren zu müssen, das plötzlich mit zwei Datenbanken kommunizieren muss .
Aber sie schaden nicht der Zuverlässigkeit. Alle Daten, auf die von vielen Stellen in Ihrem Programm verwiesen wird, können Probleme verursachen, wenn sie sich unerwartet ändern. Enumeratoren ersticken, wenn die Auflistung, die sie auflisten, in der Mitte der Aufzählung geändert wird. Event Queue Events können sich gegenseitig Streiche spielen. Threads können immer Chaos anrichten. Alles, was keine lokale Variable oder kein unveränderliches Feld ist, ist ein Problem. Globals sind solche Probleme, aber Sie werden das nicht beheben, indem Sie sie nicht global machen.
Wenn Sie in eine Datei schreiben möchten und sich der Ordnerpfad ändert, müssen die Änderungen und der Schreibvorgang synchronisiert werden. (Als eine von tausend möglichen Fehlern können Sie sagen, Sie greifen auf den Pfad zu, dann wird dieses Verzeichnis gelöscht, dann wird der Ordnerpfad in ein gutes Verzeichnis geändert, und Sie versuchen, in das gelöschte Verzeichnis zu schreiben.) Das Problem besteht darin, ob Der Ordnerpfad ist global oder einer von Tausenden, die das Programm derzeit verwendet.
Es gibt ein echtes Problem mit Feldern, auf die von verschiedenen Ereignissen in einer Warteschlange, verschiedenen Rekursionsebenen oder verschiedenen Threads zugegriffen werden kann. Einfach ausgedrückt: Lokale Variablen sind gut und Felder sind schlecht. Ehemalige globale Felder bleiben jedoch weiterhin Felder, sodass dieses (jedoch äußerst wichtige) Problem nicht für den Status "Gut" oder "Böse" globaler Felder gilt.
Zusatz: Multithreading-Probleme:
(Beachten Sie, dass bei einer Ereigniswarteschlange oder bei rekursiven Aufrufen ähnliche Probleme auftreten können, Multithreading jedoch bei weitem das schlechteste ist.) Betrachten Sie den folgenden Code:
Wenn
filePath
es sich um eine lokale Variable oder eine Konstante handelt, wird Ihr Programm bei der Ausführung nicht fehlschlagen, dafilePath
null ist. Die Prüfung funktioniert immer. Kein anderer Thread kann seinen Wert ändern. Ansonsten gibt es keine Garantien. Als ich anfing, Multithread-Programme in Java zu schreiben, bekam ich die ganze Zeit NullPointerExceptions in solchen Zeilen. IrgendeinAndere Threads können den Wert jederzeit ändern, und dies ist häufig der Fall. Wie mehrere andere Antworten zeigen, führt dies zu ernsthaften Problemen beim Testen. Die obige Aussage kann milliardenfach funktionieren, indem sie umfangreiche und umfassende Tests durchläuft und dann einmal in der Produktion in die Luft gejagt wird. Die Benutzer werden das Problem nicht reproduzieren können und es wird nicht wieder vorkommen, bis sie sich davon überzeugt haben, dass sie Dinge gesehen und vergessen haben.Globals haben definitiv dieses Problem, und wenn Sie sie vollständig beseitigen oder durch Konstanten oder lokale Variablen ersetzen können, ist das eine sehr gute Sache. Wenn auf einem Webserver statusfreier Code ausgeführt wird, ist dies wahrscheinlich möglich. In der Regel können alle Ihre Multithreading-Probleme von der Datenbank übernommen werden.
Wenn sich Ihr Programm jedoch die Daten von einer Benutzeraktion zur nächsten merken muss, haben Sie Felder, auf die alle laufenden Threads zugreifen können. Ein globales Feld in ein solches nicht-globales Feld umzuwandeln, trägt nicht zur Zuverlässigkeit bei.
quelle
Zustand ist in jeder realen Anwendung unvermeidlich. Sie können es nach Belieben zusammenfassen, eine Tabelle muss jedoch Daten in Zellen enthalten. Sie können Zellobjekte nur mit Funktionen als Schnittstelle erstellen, aber das schränkt nicht ein, an wie vielen Stellen eine Methode in der Zelle aufgerufen und die Daten geändert werden können. Sie erstellen ganze Objekthierarchien, um zu versuchen, Schnittstellen auszublenden, damit andere Teile des Codes dies nicht könnenStandardmäßig ändern Sie die Daten. Dies verhindert nicht, dass ein Verweis auf das enthaltene Objekt willkürlich weitergegeben wird. All dies beseitigt auch nicht die Probleme der Parallelität von selbst. Es erschwert zwar die Verbreitung des Zugriffs auf Daten, beseitigt jedoch nicht die wahrgenommenen Probleme mit globalen Unternehmen. Wenn jemand einen Status ändern möchte, wird er dies tun, egal ob global oder über eine komplexe API (letztere wird nur entmutigen, nicht verhindern).
Der wahre Grund, keinen globalen Speicher zu verwenden, ist die Vermeidung von Namenskollisionen. Wenn Sie mehrere Module laden, die denselben globalen Namen deklarieren, haben Sie entweder undefiniertes Verhalten (sehr schwer zu debuggen, da Komponententests bestanden werden) oder einen Linkerfehler (ich denke C - Warnt Ihr Linker oder schlägt er fehl?).
Wenn Sie Code wiederverwenden möchten, müssen Sie in der Lage sein, ein Modul von einem anderen Ort aus abzurufen, und müssen es nicht versehentlich auf Ihrem globalen Server ablegen, da dort ein Modul mit demselben Namen verwendet wird. Wenn Sie Glück haben und eine Fehlermeldung erhalten, müssen Sie nicht alle Verweise in einem Codeabschnitt ändern, um die Kollision zu verhindern.
quelle
Wenn es einfach ist, den gesamten globalen Zustand zu sehen und darauf zuzugreifen, werden Programmierer dies immer tun. Was Sie bekommen, ist unausgesprochen und es ist schwierig, Abhängigkeiten zu verfolgen (int blahblah bedeutet, dass array foo in jedem Fall gültig ist). Im Grunde genommen ist es so gut wie unmöglich, Programminvarianten zu pflegen, da alles unabhängig voneinander geändert werden kann. someInt hat eine Beziehung zwischen otherInt, die schwierig zu verwalten und zu beweisen ist, wenn Sie beide jederzeit direkt ändern können.
Das heißt, es kann getan werden (vor langer Zeit, als es in manchen Systemen der einzige Weg war), aber diese Fähigkeiten gehen verloren. Sie drehen sich hauptsächlich um Kodierungs- und Namenskonventionen - das Feld hat sich aus gutem Grund weiterentwickelt. Ihr Compiler und Linker können Invarianten in geschützten / privaten Daten von Klassen / Modulen besser überprüfen, als sich darauf zu verlassen, dass Menschen einem Masterplan folgen und die Quelle lesen.
quelle
Ich werde nicht sagen, ob globale Variablen entweder gut oder schlecht sind, aber ich werde der Diskussion hinzufügen, dass Sie wahrscheinlich viel Speicher verschwenden, wenn Sie keinen globalen Status verwenden. Besonders, wenn Sie classess verwenden, um ihre Abhängigkeiten in Feldern zu speichern.
Für den globalen Staat gibt es kein solches Problem, alles ist global.
Beispiel: Stellen Sie sich folgendes Szenario vor: Sie haben ein 10x10-Raster, das aus den Klassen "Board" und "Tile" besteht.
Wenn Sie es auf die OOP-Weise tun möchten, werden Sie wahrscheinlich das "Board" -Objekt an jedes "Tile" übergeben. Angenommen, "Tile" enthält 2 Felder vom Typ "Byte", in denen die Koordinate gespeichert ist. Der Gesamtspeicher, der auf einer 32-Bit-Maschine für eine Kachel benötigt wird, beträgt (1 + 1 + 4 = 6) Bytes: 1 für x-Koordinate, 1 für y-Koordinate und 4 für einen Zeiger auf die Karte. Dies ergibt insgesamt 600 Bytes für die Einrichtung von 10 x 10 Kacheln
Für den Fall, dass sich die Karte im globalen Bereich befindet, müsste für ein einzelnes Objekt, auf das von jeder Kachel aus zugegriffen werden kann, nur 2 Byte Speicher pro Kachel abgerufen werden. Dies sind die x- und y-Koordinatenbytes. Dies würde nur 200 Bytes ergeben.
In diesem Fall erhalten Sie also 1/3 des Speicherbedarfs, wenn Sie nur den globalen Status verwenden.
Dies ist, neben anderen Dingen, vermutlich ein Grund, warum der globale Geltungsbereich immer noch in (relativ) einfachen Sprachen wie C ++ besteht
quelle
Beim globalen Status sind mehrere Faktoren zu berücksichtigen:
Je mehr Globals du hast, desto größer ist die Chance, Duplikate einzuführen und damit Dinge zu beschädigen, wenn Duplikate nicht mehr synchron sind. Es ist sowohl notwendig als auch schmerzhaft, alle Globalen in deinem falschen menschlichen Gedächtnis zu behalten.
Immutables / write once sind im Allgemeinen in Ordnung, achten Sie jedoch auf Fehler in der Initialisierungssequenz.
Mutable Globals werden oft mit unveränderlichen Globals verwechselt ...
Eine Funktion, die Globals effektiv verwendet, verfügt über zusätzliche "versteckte" Parameter, die das Refactoring erschweren.
Der globale Staat ist nicht böse, aber er hat einen bestimmten Preis - nutzen Sie ihn, wenn der Nutzen die Kosten überwiegt.
quelle