Beim Durchsuchen von Code, den ich geschrieben habe, bin ich auf das folgende Konstrukt gestoßen, das mich zum Nachdenken gebracht hat. Auf den ersten Blick scheint es sauber genug zu sein. Ja, im eigentlichen Code hat die getLocation()
Methode einen etwas spezifischeren Namen, der genauer beschreibt, welchen Ort sie erhält.
service.setLocation(this.configuration.getLocation().toString());
In diesem Fall service
handelt es sich um eine Instanzvariable eines bekannten Typs, die innerhalb der Methode deklariert wurde. this.configuration
wird an den Klassenkonstruktor übergeben und ist eine Instanz einer Klasse, die eine bestimmte Schnittstelle implementiert (die eine öffentliche getLocation()
Methode erfordert). Daher ist der Rückgabetyp des Ausdrucks this.configuration.getLocation()
bekannt. speziell in diesem Fall ist es ein java.net.URL
, während ein service.setLocation()
will String
. Da die beiden Typen String und URL nicht direkt kompatibel sind, einige ist eine Art Umwandlung erforderlich , um den quadratischen Pflock in dem runden Loch zu passen.
Jedoch , nach dem Gesetz von Demeter , wie in der zitierten Clean Code , ein Verfahren f in der Klasse C sollten nur Methoden aufrufen C , Objekte erstellt von oder als Argumente zu übergeben f , und Objekte in Instanzvariablen gehalten C . Alles darüber hinausgehende (das letzte toString()
in meinem speziellen obigen Fall, es sei denn, Sie betrachten ein temporäres Objekt, das als Ergebnis des Methodenaufrufs selbst erstellt wurde; in diesem Fall scheint das gesamte Gesetz streitig zu sein), ist unzulässig.
Gibt es einen stichhaltigen Grund, warum ein Anruf wie der oben genannte angesichts der aufgeführten Einschränkungen abgelehnt oder sogar abgelehnt werden sollte? Oder bin ich nur zu pingelig?
Wenn ich eine Methode implementieren würde, URLToString()
die einfach toString()
ein URL
Objekt (wie das von zurückgegebene getLocation()
) aufruft , das als Parameter übergeben wurde, und das Ergebnis zurückgibt, könnte ich den getLocation()
Aufruf darin einschließen, um genau dasselbe Ergebnis zu erzielen. effektiv würde ich die umwandlung nur einen schritt nach außen verschieben. Wäre das irgendwie akzeptabel? (Es scheint mir intuitiv, dass es in keiner Weise einen Unterschied machen sollte, da sich die Dinge nur ein wenig bewegen. Nach dem zitierten Wortlaut des Gesetzes von Demeter wäre es jedoch akzeptabel, da ich würde dann direkt an einem Parameter zu einer Funktion arbeiten.)
Würde es einen Unterschied machen, wenn es sich um etwas Exotischeres handeln würde, als toString()
einen Standardtyp anzurufen?
Denken Sie bei der Beantwortung daran, dass service
es nicht praktikabel ist , das Verhalten oder die API des Typs zu ändern, von dem die Variable ist. Nehmen wir aus Gründen der Argumentation an, dass das Ändern des Rückgabetyps von getLocation()
ebenfalls unpraktisch ist.
quelle
Demeters Gesetz ist eine Gestaltungsrichtlinie, kein Gesetz, das religiös befolgt werden muss.
Wenn Sie der Meinung sind, dass Ihre Klassen ausreichend entkoppelt sind, liegt nichts an der Zeile,
this.configuration.getLocation()
insbesondere wenn es, wie Sie sagen, unpraktisch ist, andere Teile der API zu ändern.Ich bin mir ziemlich sicher, dass der Kunde vollkommen glücklich sein wird, selbst wenn Sie das Demeter-Gesetz in Stücke schneiden, solange Sie das liefern, was er will und pünktlich. Dies ist keine Entschuldigung für schlechte Software, sondern eine Mahnung, bei der Entwicklung von Software pragmatisch vorzugehen.
quelle
this.configuration
es sich um eine Instanzvariable eines Typs einer bekannten Schnittstelle handelt, ist der Aufruf einer von dieser Schnittstelle definierten Methode auch nach strenger Interpretation in Ordnung. Ja, ich weiß, dass es eine Richtlinie ist, genau wie KISS, SOLID, YAGNI und so weiter. Es gibt nur sehr wenige "Gesetze" (im rechtlichen Sinne) in der allgemeinen Softwareentwicklung.Das einzige, was ich mir vorstellen kann, keinen Code wie diesen zu schreiben, ist was, wenn
this.configuration.getLocation()
null zurückgegeben wird? Dies hängt von Ihrem Umgebungscode und der Zielgruppe ab, die diesen Code verwendet. Aber wie Marco sagt - Demeters Gesetz ist eine Faustregel - ist es gut zu befolgen, aber brechen Sie sich dabei nicht unnötig den Rücken.quelle
this.configuration.getLocation()
null zurückgegeben würde, wären wir entweder (a) höchstwahrscheinlich nie so weit gekommen, oder (b) es ist in der Zwischenzeit etwas Katastrophales passiert. In diesem Fall möchte ich, dass der Code fehlschlägt. Während dies definitiv ein allgemein gültiger Punkt ist, ist es in diesem speziellen Fall ziemlich sicher zu sagen, dass er nicht zutrifft. All dies und noch viel mehr ist ein Ausnahmehandler, der speziell für diese Art von unerwarteten Fehlern entwickelt wurde.Die strikte Befolgung des Gesetzes von Demeter würde bedeuten, dass Sie eine Methode im Konfigurationsobjekt implementieren sollten, wie:
aber ich persönlich würde mich nicht darum kümmern, weil dies eine so kleine Situation ist und eure Hände wegen der API, die ihr nicht ändern könnt, irgendwie gebunden sind. Bei Programmierregeln geht es darum, was Sie tun sollten, wenn Sie eine Wahl haben, aber manchmal haben Sie keine Wahl.
quelle