In erheblichem Maße kann ich mir keinen Grund vorstellen, ein Objekt anstelle einer statischen Klasse zu haben. Haben Objekte mehr Vorteile als ich denke? [geschlossen]

9

Ich verstehe das Konzept eines Objekts und als Java-Programmierer habe ich das Gefühl, dass das OO-Paradigma in der Praxis für mich ganz natürlich ist.

Vor kurzem dachte ich jedoch:

Moment mal, was sind die praktischen Vorteile der Verwendung eines Objekts gegenüber der Verwendung einer statischen Klasse (mit ordnungsgemäßer Kapselung und OO-Praktiken)?

Ich könnte mir zwei Vorteile der Verwendung eines Objekts vorstellen (beide sind bedeutsam und leistungsstark):

  1. Polymorphismus: Ermöglicht den dynamischen und flexiblen Austausch von Funktionen zur Laufzeit. Ermöglicht auch das einfache Hinzufügen neuer Funktionsteile und Alternativen zum System. Wenn beispielsweise eine CarKlasse für die Arbeit mit EngineObjekten entwickelt wurde und Sie dem System, das das Auto verwenden kann, eine neue Engine hinzufügen möchten, können Sie eine neue EngineUnterklasse erstellen und einfach ein Objekt dieser Klasse an das CarObjekt übergeben, ohne dies zu müssen etwas ändern Car. Und Sie können sich zur Laufzeit dafür entscheiden.

  2. In der Lage sein, Funktionen weiterzugeben: Sie können ein Objekt dynamisch im System weitergeben.

Aber gibt es weitere Vorteile für Objekte gegenüber statischen Klassen?

Wenn ich einem System neue 'Teile' hinzufüge, erstelle ich häufig eine neue Klasse und instanziiere Objekte daraus.

Aber als ich kürzlich innehielt und darüber nachdachte, wurde mir klar, dass eine statische Klasse an vielen Stellen, an denen ich normalerweise ein Objekt verwende, genauso funktioniert wie ein Objekt.

Zum Beispiel arbeite ich daran, meiner App einen Mechanismus zum Speichern / Laden von Dateien hinzuzufügen.

Bei einem Objekt sieht die aufrufende Codezeile folgendermaßen aus: Thing thing = fileLoader.load(file);

Mit einer statischen Klasse würde es so aussehen: Thing thing = FileLoader.load(file);

Was ist der Unterschied?

Ziemlich oft fällt mir einfach kein Grund ein, ein Objekt zu instanziieren, wenn eine einfache alte statische Klasse genauso handeln würde. In OO-Systemen sind statische Klassen jedoch ziemlich selten. Also muss mir etwas fehlen.

Gibt es weitere Vorteile für andere Objekte als die beiden, die ich aufgelistet habe? Bitte erkläre.

EDIT: Zur Verdeutlichung. Ich finde Objekte sehr nützlich, wenn ich Funktionen austausche oder Daten weitergebe. Zum Beispiel habe ich eine App geschrieben, die Melodien enthält. MelodyGeneratorhatte mehrere Unterklassen, die Melodien unterschiedlich erzeugen, und Objekte dieser Klassen waren austauschbar (Strategiemuster).

Die Melodien waren auch Objekte, da es nützlich ist, sie weiterzugeben. So waren die Akkorde und Skalen.

Aber was ist mit "statischen" Teilen des Systems - die nicht weitergegeben werden? Zum Beispiel - ein Mechanismus zum Speichern von Dateien. Warum sollte ich es in einem Objekt implementieren und nicht in einer statischen Klasse?

Aviv Cohn
quelle
Anstelle eines Objekts mit Feldern und möglicherweise Methoden, keinen Objekten, keinen Datensätzen, nur eine ganze Reihe von Skalarwerten, die an statische Methoden übergeben und von diesen zurückgegeben werden? Bearbeiten: Ihr neues Beispiel schlägt etwas anderes vor: Objekte, nur ohne Instanzmethoden? Ansonsten was ist Thing?
Was passiert, wenn Sie Ihre FileLoadergegen eine austauschen müssen, die aus einem Socket liest? Oder ein Mock zum Testen? Oder eine, die eine Zip-Datei öffnet?
Benjamin Hodgson
1
@delnan Okay, ich habe eine Frage herausgefunden, deren Antwort mir helfen wird zu verstehen: Warum sollten Sie einen 'statischen' Teil des Systems als Objekt implementieren? Wie das Beispiel in der Frage: ein Mechanismus zum Speichern von Dateien. Was bringt es mir, wenn ich es in einem Objekt implementiere?
Aviv Cohn
1
Standardmäßig sollte ein nicht statisches Objekt verwendet werden. Verwenden Sie statische Klassen nur, wenn Sie der Meinung sind, dass dies Ihre Absicht wirklich besser ausdrückt. System.Mathin .NET ist ein Beispiel für etwas, das als statische Klasse viel sinnvoller ist: Sie müssen es nie austauschen oder verspotten, und keiner der Vorgänge kann logischerweise Teil einer Instanz sein. Ich glaube wirklich nicht, dass Ihr "Spar" -Beispiel zu dieser Rechnung passt.
Benjamin Hodgson

Antworten:

14

lol du klingst wie ein Team, an dem ich gearbeitet habe;)

Java (und wahrscheinlich C #) unterstützt diesen Programmierstil auf jeden Fall. Und ich arbeite mit Leuten, deren erster Instinkt lautet: "Ich kann das zu einer statischen Methode machen!" Aber es gibt einige subtile Kosten, die Sie im Laufe der Zeit einholen.

1) Java ist eine objektorientierte Sprache. Und es macht die funktionalen Jungs verrückt, aber es hält wirklich ziemlich gut. Die Idee hinter OO besteht darin, Funktionalität mit Status zu bündeln, um kleine Daten- und Funktionseinheiten zu erhalten, die ihre Semantik beibehalten, indem der Status ausgeblendet und nur die Funktionen angezeigt werden, die in diesem Kontext sinnvoll sind.

Wenn Sie zu einer Klasse mit nur statischen Methoden wechseln, brechen Sie den "Zustand" -Teil der Gleichung. Aber der Staat muss noch irgendwo leben. Was ich im Laufe der Zeit gesehen habe, ist, dass eine Klasse mit allen statischen Methoden immer kompliziertere Parameterlisten hat, weil sich der Status von der Klasse in die Funktionsaufrufe bewegt.

Nachdem Sie eine Klasse mit allen statischen Methoden erstellt haben, führen Sie sie durch und untersuchen Sie einfach, wie viele dieser Methoden einen einzigen gemeinsamen Parameter haben. Es ist ein Hinweis darauf, dass dieser Parameter entweder die enthaltende Klasse für diese Funktionen sein sollte oder dass dieser Parameter ein Attribut einer Instanz sein sollte.

2) Die Regeln für OO sind ziemlich gut verstanden. Nach einer Weile können Sie sich ein Klassendesign ansehen und feststellen, ob es Kriterien wie SOLID erfüllt. Und nach vielen Tests mit Übungseinheiten entwickeln Sie ein gutes Gefühl dafür, was eine Klasse "richtig groß" und "kohärent" macht. Aber es gibt keine guten Regeln für eine Klasse mit allen statischen Methoden und keinen wirklichen Grund, warum Sie nicht einfach alles darin bündeln sollten. Die Klasse ist in Ihrem Editor geöffnet. Was zum Teufel? Fügen Sie dort einfach Ihre neue Methode hinzu. Nach einer Weile verwandelt sich Ihre Anwendung in eine Reihe konkurrierender "Gottobjekte", von denen jedes versucht, die Welt zu dominieren. Auch hier ist die Umgestaltung in kleinere Einheiten sehr subjektiv und schwer zu sagen, ob Sie es richtig verstanden haben.

3) Schnittstellen sind eine der leistungsstärksten Funktionen von Java. Die Klassenvererbung hat sich als problematisch erwiesen, aber das Programmieren mit Schnittstellen bleibt einer der mächtigsten Tricks der Sprache. (dito C #) All-statische Klassen können sich nicht in dieses Modell einfügen.

4) Es schlägt die Tür zu wichtigen OO-Techniken zu, die Sie nicht nutzen können. Sie können also jahrelang nur mit einem Hammer in Ihrem Werkzeugkasten arbeiten, ohne zu wissen, wie viel einfacher es gewesen wäre, wenn Sie auch einen Schraubenzieher gehabt hätten.

4.5) Es werden die schwierigsten und unzerbrechlichsten Abhängigkeiten zur Kompilierungszeit erstellt. Wenn Sie dies beispielsweise getan haben, FileSystem.saveFile()gibt es keine Möglichkeit, dies zu ändern, außer Ihre JVM zur Laufzeit vorzutäuschen. Dies bedeutet, dass jede Klasse, die auf Ihre statische Funktionsklasse verweist, eine harte Abhängigkeit zur Kompilierungszeit von dieser spezifischen Implementierung hat, was eine Erweiterung fast unmöglich macht und das Testen enorm erschwert. Sie können die statische Klasse isoliert testen, es wird jedoch sehr schwierig, die Klassen, die auf diese Klasse verweisen, isoliert zu testen.

5) Sie werden Ihre Mitarbeiter verrückt machen. Die meisten Fachleute, mit denen ich zusammenarbeite, nehmen ihren Code ernst und achten zumindest auf einige Designprinzipien. Wenn sie die Kernabsicht einer Sprache beiseite lassen, ziehen sie sich die Haare aus, weil sie den Code ständig überarbeiten.

Wenn ich in einer Sprache bin, versuche ich immer, eine Sprache gut zu verwenden. Wenn ich zum Beispiel in Java bin, verwende ich gutes OO-Design, weil ich dann die Sprache wirklich für das nutze, was sie tut. Wenn ich in Python bin, mische ich Funktionen auf Modulebene mit gelegentlichen Klassen - ich konnte nur Klassen in Python schreiben, aber dann würde ich die Sprache nicht für das verwenden, was sie kann.

Eine andere Taktik besteht darin, eine Sprache schlecht zu benutzen, und sie beschweren sich über alle Probleme, die sie verursacht. Das gilt aber für so ziemlich jede Technologie.

Das Hauptmerkmal von Java ist die Verwaltung der Komplexität in kleinen, testbaren Einheiten, die zusammen hängen, damit sie leicht zu verstehen sind. Java betont klare Schnittstellendefinitionen unabhängig von der Implementierung - was ein großer Vorteil ist. Deshalb wird es (und andere ähnliche OO-Sprachen) weiterhin so häufig verwendet. Bei aller Ausführlichkeit und Ritualität habe ich immer das Gefühl, dass die Ideen im Code sauberer getrennt sind als meine Projekte in einer dynamischeren Sprache, wenn ich mit einer großen Java-App fertig bin.

Es ist jedoch eine schwierige Frage. Ich habe gesehen, wie Leute den "all statischen" Fehler bekommen haben, und es ist ziemlich schwierig, sie davon abzubringen. Aber ich habe gesehen, dass sie ein großes Gefühl der Erleichterung haben, wenn sie darüber hinwegkommen.

rauben
quelle
Sie sprechen hauptsächlich davon, Dinge klein und modular zu halten und Status und Funktionalität zusammenzuhalten. Nichts hindert mich daran, dies mit statischen Klassen zu tun. Sie können Staat haben. Und Sie können sie mit Getter-Setter kapseln. Und Sie können das System in kleine Klassen unterteilen, die Funktionalität und Status enthalten. All dies gilt sowohl für Klassen als auch für Objekte. Und genau das ist mein Dilemma: Angenommen, ich füge meiner App neue Funktionen hinzu. Offensichtlich wird es in einer separaten Klasse gehen, um SRP zu gehorchen. Aber warum genau sollte ich diese Klasse instanziieren? Das verstehe ich nicht.
Aviv Cohn
Ich meine: Manchmal ist klar, warum ich Objekte will. Ich werde das Beispiel aus der Bearbeitung für meine Frage verwenden: Ich hatte eine App, die Melodien zusammensetzt. Es gab verschiedene Skalen, die ich in die MelodyGenerators einstecken konnte, um verschiedene Melodien zu erzeugen. Und die Melodien waren Objekte, also konnte ich sie in einen Stapel legen und wieder alte spielen usw. In solchen Fällen ist mir klar, warum ich Objekte verwenden sollte. Was ich nicht verstehe, ist, warum ich Objekte verwenden sollte, um 'statische' Teile des Systems darzustellen: z. B. einen Mechanismus zum Speichern von Dateien. Warum sollte dies nicht nur eine statische Klasse sein?
Aviv Cohn
Eine Klasse mit statischen Methoden muss ihren Status externalisieren. Was manchmal eine sehr wichtige Faktorisierungstechnik ist. Meistens möchten Sie jedoch den Status kapseln. Ein konkretes Beispiel: Vor Jahren schrieb ein Mitarbeiter eine "Datumsauswahl" in Javascript. Und es war ein Albtraum. Die Kunden beschwerten sich ständig darüber. Also habe ich es in "Kalender" -Objekte umgestaltet und plötzlich mehrere davon instanziiert, nebeneinander gestellt, zwischen Monaten und Jahren gesprungen usw. Es war so reichhaltig, dass wir tatsächlich Funktionen deaktivieren mussten. Instanziierung gibt Ihnen diese Skala.
Rob
3
"Die Idee hinter OO besteht darin, Funktionalität mit Status zu bündeln, um kleine Daten- und Funktionseinheiten zu erhalten, die ihre Semantik beibehalten, indem Status ausgeblendet und nur die Funktionen angezeigt werden, die in diesem Kontext sinnvoll sind." Das ist grundsätzlich falsch. OO impliziert keinen veränderlichen Zustand und die Abstraktion ist nicht exklusiv für OO. Es gibt zwei Möglichkeiten, eine Abstraktion zu erreichen, und Objekte sind nur eine davon (die andere sind abstrakte Datentypen).
Doval
1
@Doval Ich verstehe nicht, warum jede Diskussion über OO notwendigerweise zu einer Diskussion über funktionale Programmierung werden muss.
Rob
6

Du hast gefragt:

Aber gibt es weitere Vorteile für Objekte gegenüber statischen Klassen?

Vor dieser Frage aufgeführt Sie Polymorphismus und herumgereicht werden als zwei Vorteile der Verwendung von Objekten. Ich möchte sagen, dass dies die Merkmale des OO-Paradigmas sind. Die Kapselung ist ein weiteres Merkmal des OO-Paradigmas.

Dies sind jedoch nicht die Vorteile. Die Vorteile sind:

  1. Bessere Abstraktionen
  2. Bessere Wartbarkeit
  3. Bessere Testbarkeit

Du sagtest:

Aber als ich kürzlich innehielt und darüber nachdachte, wurde mir klar, dass eine statische Klasse an vielen Stellen, an denen ich normalerweise ein Objekt verwende, genauso funktioniert wie ein Objekt.

Ich denke, Sie haben dort einen gültigen Punkt. Programmierung ist im Kern nichts anderes als die Transformation von Daten und die Erzeugung von Nebenwirkungen basierend auf Daten. Manchmal erfordert das Transformieren von Daten Hilfsdaten. In anderen Fällen ist dies nicht der Fall.

Wenn Sie sich mit der ersten Kategorie von Transformationen befassen, müssen die Hilfsdaten entweder als Eingabe übergeben oder irgendwo gespeichert werden. Ein Objekt ist der bessere Ansatz als statische Klassen für solche Transformationen. Ein Objekt kann die Hilfsdaten speichern und zum richtigen Zeitpunkt verwenden.

Für die zweite Kategorie von Transformationen ist eine statische Klasse so gut wie ein Objekt, wenn nicht sogar besser. Mathematische Funktionen sind klassische Beispiele für diese Kategorie. Die meisten Standardfunktionen der C-Bibliothek fallen ebenfalls in diese Kategorie.

Du hast gefragt:

Bei einem Objekt sieht die aufrufende Codezeile folgendermaßen aus: Thing thing = fileLoader.load(file);

Mit einer statischen Klasse würde es so aussehen: Thing thing = FileLoader.load(file);

Was ist der Unterschied?

Wenn FileLoadernicht, überhaupt , müssen alle Daten speichern, ich mit dem zweiten Ansatz gehen würde. Wenn die Wahrscheinlichkeit gering ist, dass für die Durchführung der Operation Zusatzdaten benötigt werden, ist der erste Ansatz sicherer.

Du hast gefragt:

Gibt es weitere Vorteile für andere Objekte als die beiden, die ich aufgelistet habe? Bitte erkläre.

Ich habe die Vorteile (Vorteile) der Verwendung des OO-Paradigmas aufgelistet. Ich hoffe, sie sind selbsterklärend. Wenn nicht, werde ich gerne näher darauf eingehen.

Du hast gefragt:

Aber was ist mit "statischen" Teilen des Systems - die nicht weitergegeben werden? Zum Beispiel - ein Mechanismus zum Speichern von Dateien. Warum sollte ich es in einem Objekt implementieren und nicht in einer statischen Klasse?

Dies ist ein Beispiel, in dem eine statische Klasse einfach nicht ausreicht. Es gibt viele Möglichkeiten, Ihre Anwendungsdaten in einer Datei zu speichern:

  1. Speichern Sie es in einer CSV-Datei.
  2. Speichern Sie es in einer XML-Datei.
  3. Speichern Sie es in einer JSON-Datei.
  4. Speichern Sie es als Binärdatei mit direktem Speicherauszug der Daten.
  5. Speichern Sie es direkt in einer Tabelle in einer Datenbank.

Die einzige Möglichkeit, solche Optionen bereitzustellen, besteht darin, eine Schnittstelle zu erstellen und Objekte zu erstellen, die die Schnittstelle implementieren.

Abschließend

Verwenden Sie den richtigen Ansatz für das jeweilige Problem. Es ist besser, nicht religiös über einen Ansatz gegen den anderen zu sein.

R Sahu
quelle
Auch, wenn Bedarf vieler verschiedenen Objekttypen (Klassen) gespeichert werden (zB Melody, Chord, Improvisations, SoundSampleund andere), dann wird es wirtschaftlich sein , die Umsetzung über Abstraktionen zu vereinfachen.
Rwong
5

Manchmal hängt es von der Sprache und dem Kontext ab. Beispielsweise haben PHPSkripte, die zum Bearbeiten von Anforderungen verwendet werden, immer eine Anforderung zum Bearbeiten und eine Antwort zum Generieren während der gesamten Lebensdauer des Skripts. Daher können statische Methoden zum Bearbeiten der Anforderung und zum Generieren einer Antwort geeignet sein. Auf einem Server, auf den geschrieben wurde Node.js, können jedoch viele verschiedene Anforderungen und Antworten gleichzeitig vorliegen. Die erste Frage lautet also: Sind Sie sicher, dass die statische Klasse wirklich einem Singleton-Objekt entspricht?

Zweitens können Sie mit Singletons mithilfe von Objekten den Polymorphismus mithilfe von Techniken wie Dependency_injection und Factory_method_pattern nutzen . Dies wird häufig in verschiedenen Inversion_of_control- Mustern verwendet und ist nützlich, um Scheinobjekte zum Testen, Protokollieren usw. zu erstellen.

Sie haben die oben genannten Vorteile erwähnt. Hier ist eine, die Sie nicht erwähnt haben: Vererbung. Viele Sprachen können statische Methoden nicht so überschreiben, wie Instanzmethoden überschrieben werden können. Im Allgemeinen ist es viel schwieriger, statische Methoden zu erben und zu überschreiben.

Gregory Magarshak
quelle
Danke für die Antwort. Ihrer Meinung nach: Wenn Sie einen "statischen" Teil des Systems erstellen, wird etwas nicht "herumgereicht" - zum Beispiel der Teil des Systems, der Sounds wiedergibt, oder der Teil des Systems, der Daten in einer Datei speichert: soll ich es in einem Objekt oder in einer statischen Klasse implementieren?
Aviv Cohn
3

Zusätzlich zu Rob Ys Post


Solange die Funktionalität von Ihnen load(File file)klar von allen anderen von Ihnen verwendeten Funktionen getrennt werden kann, ist es in Ordnung, eine statische Methode / Klasse zu verwenden. Sie externalisieren den Status (was keine schlechte Sache ist) und erhalten auch keine Redundanz, da Sie beispielsweise Ihre Funktion teilweise anwenden oder curry können, damit Sie sich nicht wiederholen müssen. (das ist eigentlich das gleiche oder ähnlich wie bei der Verwendung eines factoryMusters)

Sobald jedoch zwei dieser Funktionen allgemein verwendet werden, möchten Sie sie irgendwie gruppieren können. Stellen Sie sich vor, Sie haben nicht nur eine loadFunktion, sondern auch eine hasValidSyntaxFunktion. Was wirst du tun?

     if (FileLoader.hasValidSyntax(myfile))
          Thing thing = FileLoader.load(myfile);
     else
          println "oh noes!"

Sehen Sie die beiden Verweise myfilehier? Sie beginnen sich zu wiederholen, weil Ihr externer Status für jeden Anruf übergeben werden muss. Rob Y hat beschrieben, wie Sie den Zustand (hier den file) verinnerlichen , damit Sie es so machen können:

     FileLoader myfileLoader = new FileLoader(myfile)
     if (myfileLoader.hasValidSyntax())
          Thing thing = myfileLoader.load();
     else
          println "oh noes!"
Valenterry
quelle
Das gleiche Objekt zweimal passieren zu müssen, ist ein oberflächliches Symptom; das eigentliche Problem ist dies darauf hinweisen könnte , dass einige Arbeit redundant ausgeführt wird - die Datei möglicherweise zweimal geöffnet werden müssen, zweimal analysiert und zweimal geschlossen, wenn hasValidSyntax()und load()sind nicht auf die Wiederverwendung Zustand (das Ergebnis einer teilweise analysierten Datei) erlaubt.
Rwong
2

Ein wichtiges Thema , wenn statische Klassen ist , dass sie zwingen Sie Ihre Abhängigkeiten zu verbergen, und zwingen Sie auf Implementierungen abhängen. Welche Abhängigkeiten bestehen in der folgenden Konstruktorsignatur:

public Person(String name)

Nach der Unterschrift zu urteilen, braucht eine Person nur einen Namen, oder? Nun, nicht wenn die Implementierung ist:

public Person(String name) {
    ResultSet rs = DBConnection.getPersonFilePathByName(name);
    File f = FileLoader.load(rs.getPath());
    PersonData.setDataFile(f);
    this.name = name;
    this.age = PersonData.getAge();
}

Eine Person wird also nicht nur instanziiert. Wir ziehen tatsächlich Daten aus einer Datenbank, die uns einen Pfad zu einer Datei gibt, die dann analysiert werden muss, und dann müssen die tatsächlichen Daten, die wir wollen, herausgeputzt werden. Dieses Beispiel ist deutlich übertrieben, aber es beweist den Punkt. Aber warte, es kann noch so viel mehr geben! Ich schreibe folgenden Test:

public void testPersonConstructor() {
    Person p = new Person("Milhouse van Houten");
    assertEqual(10, p.age);
}

Das sollte aber passieren, oder? Ich meine, wir haben all das andere Zeug gekapselt, oder? Nun, eigentlich explodiert es mit einer Ausnahme. Warum? Oh ja, die versteckten Abhängigkeiten, von denen wir nichts wussten, haben einen globalen Zustand. Die DBConnectionBedürfnisse werden initialisiert und verbunden. Die FileLoaderAnforderungen werden mit einem FileFormatObjekt (wie XMLFileFormatoder CSVFileFormat) initialisiert . Noch nie davon gehört? Nun, das ist der Punkt. Ihr Code (und Ihr Compiler) können Ihnen nicht sagen, dass Sie diese Dinge benötigen, da die statischen Aufrufe diese Abhängigkeiten verbergen. Habe ich Test gesagt? Ich meinte, dass der neue Junior-Entwickler in Ihrer letzten Version so etwas ausgeliefert hat. Immerhin funktioniert kompiliert =, oder?

Angenommen, Sie befinden sich auf einem System, auf dem keine MySQL-Instanz ausgeführt wird. Angenommen, Sie befinden sich auf einem Windows-System, aber Ihre DBConnectionKlasse wird nur auf einer Linux-Box (mit Linux-Pfaden) an Ihren MySQL-Server gesendet. Oder sagen Sie, Sie befinden sich auf einem System, auf dem der vom zurückgegebene Pfad DBConnectionnicht für Sie gelesen / geschrieben wird. Das bedeutet, dass der Versuch, dieses System unter einer dieser Bedingungen auszuführen oder zu testen, fehlschlägt, nicht aufgrund eines Codefehlers, sondern aufgrund eines Entwurfsfehlers, der die Flexibilität des Codes einschränkt und Sie an eine Implementierung bindet.

Angenommen, wir möchten jeden Aufruf der Datenbank für eine bestimmte PersonInstanz protokollieren, die einen bestimmten, problematischen Pfad durchläuft. Wir könnten DBConnectionuns anmelden, aber dies wird alles protokollieren , viel Unordnung verursachen und es schwierig machen, den bestimmten Codepfad zu unterscheiden, den wir verfolgen möchten. Wenn wir jedoch die Abhängigkeitsinjektion mit einer DBConnectionInstanz verwenden, können wir die Schnittstelle einfach in einem Dekorator implementieren (oder die Klasse erweitern, da beide Optionen für ein Objekt verfügbar sind). Mit einer statischen Klasse können wir die Abhängigkeit nicht einfügen, wir können keine Schnittstelle implementieren, wir können sie nicht in einen Dekorator einschließen und wir können die Klasse nicht erweitern. Wir können es nur direkt aufrufen, irgendwo tief in unserem Code versteckt. So sind wir gezwungen eine versteckte Abhängigkeit von einer Implementierung haben.

Ist das immer schlecht Nicht unbedingt, aber es könnte besser sein, Ihren Standpunkt umzukehren und zu sagen: "Gibt es einen guten Grund, warum dies keine Instanz sein sollte?" anstatt : „Gibt es einen guten Grund , dies sollte eine Instanz sein?“ Wenn Sie wirklich sagen können, dass Ihr Code Math.abs()sowohl in seiner Implementierung als auch in der Art und Weise, wie er verwendet wird, so unerschütterlich (und zustandslos) ist , können Sie in Betracht ziehen, ihn statisch zu machen. Wenn Sie jedoch Instanzen über statische Klassen haben, erhalten Sie eine Welt der Flexibilität, die nachträglich nicht immer wieder leicht zu erfassen ist. Es kann Ihnen auch mehr Klarheit über die wahre Natur der Abhängigkeiten Ihres Codes geben.

cbojar
quelle
Versteckte Abhängigkeiten sind extrem gute Punkte. Fast hätte ich meine Redewendung vergessen: "Die Qualität des Codes sollte daran gemessen werden, wie er verwendet wird und nicht daran, wie er implementiert wird."
Euphoric
Aber auch in einer nicht statischen Klasse können versteckte Abhängigkeiten existieren, oder? Ich verstehe also nicht, warum dies ein Nachteil von statischen Klassen wäre, aber nicht von nicht statischen Klassen.
Valenterry
@valenterry Ja, wir können auch nicht statische Abhängigkeiten ausblenden, aber der entscheidende Punkt ist, dass das Ausblenden nicht statischer Abhängigkeiten eine Wahl ist . Ich könnte neweine Reihe von Objekten im Konstruktor aufbauen (was im Allgemeinen nicht ratsam ist), aber ich kann sie auch injizieren. Bei statischen Klassen gibt es keine Möglichkeit, sie einzufügen (in Java sowieso nicht einfach, und das wäre eine ganz andere Diskussion für Sprachen, die dies zulassen), daher gibt es keine Wahl. Deshalb habe ich die Idee hervorzuheben ist gezwungen , in meiner Antwort so stark in das Verstecken Abhängigkeiten.
Cbojar
Sie können sie jedoch jedes Mal einfügen, wenn Sie die Methode aufrufen, indem Sie sie als Argumente angeben. Sie sind also nicht gezwungen, sie zu verbergen, sondern sie explizit zu machen, damit jeder "aha, diese Methode hängt von diesen Argumenten ab" und nicht "aha, diese Methode hängt von diesen (Teil-) Argumenten und einem verborgenen Zwischenzustand ab, den ich nicht kenne kennt".
Valenterry
In Java können Sie meines Wissens keine statische Klasse als Parameter angeben, ohne eine ganze Reflexions-Rigmarole zu durchlaufen. (Ich habe alles versucht, was mir einfällt. Wenn Sie einen Weg haben, würde ich ihn gerne sehen.) Und wenn Sie sich dafür entscheiden, untergraben Sie im Wesentlichen entweder das integrierte Typsystem (der Parameter ist a Class, dann stellen wir sicher, dass es die richtige Klasse ist) oder Sie tippen Enten (wir stellen sicher, dass es auf die richtige Methode reagiert). Wenn Sie Letzteres tun möchten, sollten Sie Ihre Sprachwahl neu bewerten. Wenn Sie das erstere tun möchten, funktionieren Instanzen
einwandfrei
1

Nur meine zwei Cent.

Für Ihre Frage:

Aber was ist mit "statischen" Teilen des Systems - die nicht weitergegeben werden? Zum Beispiel - ein Mechanismus zum Speichern von Dateien. Warum sollte ich es in einem Objekt implementieren und nicht in einer statischen Klasse?

Sie können sich fragen, ob sich der Mechanismus des Teils des Systems, der abgespielt wird, oder der Teil des Systems, der Daten in einer Datei speichert, ändert . Wenn Ihre Antwort Ja lautet, bedeutet dies, dass Sie sie mit abstract class/ abstrahieren sollten interface. Sie fragen sich vielleicht, wie kann ich die zukünftigen Dinge wissen? Auf keinen Fall können wir. Wenn das java.lang.MathObjekt also zustandslos ist, können Sie eine 'statische Klasse' verwenden, z. B. einen objektorientierten Ansatz.

user3663635
quelle
Es gibt einen ironischen Rat: Drei Schläge und Sie Refactor , was darauf hindeutet, dass man warten kann, bis die Änderung tatsächlich benötigt wird. Was ich unter "Ändern" verstehe, ist: Es muss mehr als ein Objekttyp gespeichert werden. oder in mehr als einem Dateiformat (Speichertyp) speichern müssen; oder eine drastische Zunahme der Komplexität gespeicherter Daten. Wenn man ziemlich sicher ist, dass die Änderung bald eintreten wird, kann man natürlich ein flexibleres Design im Vorfeld einbeziehen.
Rwong