Vor ein paar Monaten habe ich angefangen, in einem neuen Projekt zu arbeiten, und als ich den Code durchgesehen habe, habe ich die Menge der verwendeten statischen Methoden gemerkt. In ihnen sind nicht nur Utility-Methoden collectionToCsvString(Collection<E> elements)
, sondern auch viele Geschäftslogiken enthalten.
Als ich den Verantwortlichen nach den Hintergründen fragte, sagte er, es sei ein Ausweg aus der Tyrannei des Frühlings . Um diesen Denkprozess dreht sich etwas: Um eine Methode zur Erstellung von Kundenbelegen zu implementieren, könnten wir einen Service haben
@Service
public class CustomerReceiptCreationService {
public CustomerReceipt createReceipt(Object... args) {
CustomerReceipt receipt = new CustomerReceipt();
// creation logic
return receipt;
}
}
Nun, der Typ sagte, dass er es nicht mag, Klassen unnötigerweise von Spring verwalten zu lassen, da dies die Einschränkung auferlegt, dass Client-Klassen selbst Spring Beans sein müssen. Am Ende wird alles von Spring verwaltet, was uns ziemlich zwingt, prozedural mit staatenlosen Objekten zu arbeiten. Mehr oder weniger, was hier angegeben ist https://www.javacodegeeks.com/2011/02/domain-driven-design-spring-aspectj.html
Anstelle des obigen Codes hat er also
public class CustomerReceiptCreator {
public static CustomerReceipt createReceipt(Object... args) {
CustomerReceipt receipt = new CustomerReceipt();
// creation logic
return receipt;
}
}
Ich könnte bis zu dem Punkt argumentieren, dass Spring es nach Möglichkeit vermeiden sollte, unsere Klassen zu managen, aber ich sehe nicht den Vorteil, dass alles statisch ist. Diese statischen Methoden sind auch zustandslos, also auch nicht sehr OO. Ich würde mich mit sowas wohler fühlen als
new CustomerReceiptCreator().createReceipt()
Er behauptet, dass statische Methoden einige zusätzliche Vorteile haben. Nämlich:
- Einfacher zu lesen. Importieren Sie die statische Methode und wir müssen uns nur um die Aktion kümmern, nicht um welche Klasse.
- Ist natürlich eine Methode frei von DB-Aufrufen, also leistungsmäßig günstig; und es ist eine gute Sache, es klar zu machen, so dass der potenzielle Client in den Code gehen und dies überprüfen muss.
- Einfacheres Schreiben von Tests.
Ich habe jedoch das Gefühl, dass etwas nicht ganz in Ordnung ist, daher würde ich gerne einige erfahrene Entwickler dazu hören.
Meine Frage ist also, was sind die potenziellen Tücken dieser Art der Programmierung?
quelle
static
Methode ist nur eine normale Factory-Methode. Die Statisierung von Factory-Methoden ist aus einer Reihe von zwingenden Gründen die allgemein anerkannte Konvention. Ob die Fabrikmethode hier angemessen ist, ist eine andere Sache.Antworten:
Was ist der Unterschied zwischen
new CustomerReceiptCreator().createReceipt()
undCustomerReceiptCreator.createReceipt()
? So ziemlich keine. Der einzige wesentliche Unterschied besteht darin, dass der erste Fall eine erheblich umständlichere Syntax aufweist. Wenn Sie der ersten Überzeugung folgen, dass das Vermeiden statischer Methoden Ihren Code besser macht, irren Sie sich ernsthaft. Das Erstellen eines Objekts zum Aufrufen einer einzelnen Methode ist eine statische Methode mit stumpfer Syntax.Wo die Dinge anders werden, ist, wenn Sie injizieren,
CustomerReceiptCreator
anstattnew
es zu tun . Betrachten wir ein Beispiel:Vergleichen wir dies mit einer statischen Methodenversion:
Der Vorteil der statischen Version ist, dass ich Ihnen leicht sagen kann, wie sie mit dem Rest des Systems interagiert. Das tut es nicht. Wenn ich keine globalen Variablen verwendet habe, weiß ich, dass der Rest des Systems nicht irgendwie geändert wurde. Ich weiß, dass hier kein anderer Teil des Systems den Beleg beeinflusst. Wenn ich unveränderliche Objekte verwendet habe, weiß ich, dass sich die Reihenfolge nicht geändert hat und dass createReceipt eine reine Funktion ist. In diesem Fall kann ich diesen Aufruf frei verschieben / entfernen / usw., ohne mir Sorgen über zufällige unvorhersehbare Effekte an anderer Stelle zu machen.
Ich kann nicht die gleichen Garantien geben, wenn ich das gespritzt habe
CustomerReceiptCreator
. Es hat möglicherweise einen internen Status, der durch den Aufruf geändert wird, ich bin möglicherweise von einem anderen Status betroffen oder ändere ihn. Es kann unvorhersehbare Beziehungen zwischen Anweisungen in meiner Funktion geben, sodass das Ändern der Reihenfolge zu überraschenden Fehlern führt.Was passiert dagegen, wenn
CustomerReceiptCreator
plötzlich eine neue Abhängigkeit benötigt wird? Angenommen, es muss ein Feature-Flag überprüft werden. Wenn wir spritzen, könnten wir etwas machen wie:Dann sind wir fertig, denn dem aufrufenden Code wird ein injiziert,
CustomerReceiptCreator
der automatisch ein injiziert wirdFeatureFlags
.Was wäre, wenn wir eine statische Methode verwenden würden?
Aber warte! Der aufrufende Code muss ebenfalls aktualisiert werden:
Natürlich bleibt die Frage offen, woher sie
processOrder
kommtFeatureFlags
. Wenn wir Glück haben, endet der Trail hier. Wenn nicht, wird die Notwendigkeit, FeatureFlags zu passieren, weiter nach oben geschoben.Hier gibt es einen Kompromiss. Statische Methoden, bei denen die Abhängigkeiten explizit weitergegeben werden müssen, was zu mehr Arbeit führt. Eingespritzte Methoden reduzieren die Arbeit, machen jedoch die Abhängigkeiten implizit und damit verborgen, was das Ermitteln von Code erschwert.
quelle