it-swarm.com.de

Begründung, lokale Variablen gegenüber Instanzvariablen zu bevorzugen?

Die Codebasis, an der ich arbeite, verwendet häufig Instanzvariablen, um Daten zwischen verschiedenen trivialen Methoden auszutauschen. Der ursprüngliche Entwickler ist fest davon überzeugt, dass dies den Best Practices entspricht, die im Buch Clean Code von Onkel Bob/Robert Martin angegeben sind: "Die erste Regel für Funktionen lautet, dass sie klein sein sollten." und "Die ideale Anzahl von Argumenten für eine Funktion ist Null (niladisch). (...) Argumente sind hart. Sie erfordern viel konzeptionelle Kraft."

Ein Beispiel:

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  private byte[] encodedData;
  private EncryptionInfo encryptionInfo;
  private EncryptedObject payloadOfResponse;
  private URI destinationURI;

  public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    checkNotNull(encryptedRequest);

    getEncodedData(encryptedRequest);
    getEncryptionInfo();
    getDestinationURI();
    passRequestToServiceClient();

    return cryptoService.encryptResponse(payloadOfResponse);
  }

  private void getEncodedData(EncryptedRequest encryptedRequest) {
    encodedData = cryptoService.decryptRequest(encryptedRequest, byte[].class);
  }

  private void getEncryptionInfo() {
    encryptionInfo = cryptoService.getEncryptionInfoForDefaultClient();
  }

  private void getDestinationURI() {
    destinationURI = router.getDestination().getUri();
  }

  private void passRequestToServiceClient() {
    payloadOfResponse = serviceClient.handle(destinationURI, encodedData, encryptionInfo);
  }
}

Ich würde das mit lokalen Variablen wie folgt umgestalten:

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    checkNotNull(encryptedRequest);

    byte[] encodedData = cryptoService.decryptRequest(encryptedRequest, byte[].class);
    EncryptionInfo encryptionInfo = cryptoService.getEncryptionInfoForDefaultClient();
    URI destinationURI = router.getDestination().getUri();
    EncryptedObject payloadOfResponse = serviceClient.handle(destinationURI, encodedData,
      encryptionInfo);

    return cryptoService.encryptResponse(payloadOfResponse);
  }
}

Dies ist kürzer, beseitigt die implizite Datenkopplung zwischen den verschiedenen trivialen Methoden und begrenzt die variablen Bereiche auf das erforderliche Minimum. Trotz dieser Vorteile kann ich den ursprünglichen Entwickler immer noch nicht davon überzeugen, dass dieses Refactoring gerechtfertigt ist, da es den oben erwähnten Praktiken von Onkel Bob zu widersprechen scheint.

Daher meine Fragen: Was ist die objektive wissenschaftliche Begründung, um lokale Variablen gegenüber Instanzvariablen zu bevorzugen? Ich kann nicht ganz meinen Finger darauf legen. Meine Intuition sagt mir, dass versteckte Kopplungen schlecht sind und dass ein enger Bereich besser ist als ein breiter. Aber was ist die Wissenschaft, um dies zu unterstützen?

Und umgekehrt, gibt es Nachteile bei diesem Refactoring, die ich möglicherweise übersehen habe?

113
Alexander

Was ist die objektive wissenschaftliche Begründung, um lokale Variablen gegenüber Instanzvariablen zu bevorzugen?

Der Bereich ist kein binärer Zustand, sondern ein Farbverlauf. Sie können diese vom größten zum kleinsten ordnen:

Global > Class > Local (method) > Local (code block, e.g. if, for, ...)

Bearbeiten: Was ich als "Klassenbereich" bezeichne, ist das, was Sie unter "Instanzvariable" verstehen. Meines Wissens sind das auch, aber ich bin ein C # -Entwickler, kein Java -Entwickler. Der Kürze halber habe ich alle Statiken in die globale Kategorie eingeordnet, da Statiken nicht das Thema der Frage sind.

Je kleiner der Umfang, desto besser. Das Grundprinzip ist, dass Variablen sollten im kleinstmöglichen Bereich leben. Dies hat viele Vorteile:

  • Es zwingt Sie, über die Verantwortung der aktuellen Klasse nachzudenken, und hilft Ihnen, sich an SRP zu halten.
  • Dadurch müssen Sie globale Namenskonflikte, z. Wenn zwei oder mehr Klassen eine Name -Eigenschaft haben, müssen Sie ihnen keine Präfixe wie FooName, BarName, ... voranstellen. So bleiben Ihre Variablennamen sauber und knapp wie möglich.
  • Der Code wird dekodiert, indem die verfügbaren Variablen (z. B. für Intellisense) auf diejenigen beschränkt werden, die für den Kontext relevant sind.
  • Es ermöglicht eine Form der Zugriffskontrolle, sodass Ihre Daten nicht von einem Akteur manipuliert werden können, den Sie nicht kennen (z. B. einer anderen von einem Kollegen entwickelten Klasse).
  • Dadurch wird der Code besser lesbar, da Sie sicherstellen, dass die Deklaration dieser Variablen versucht, der tatsächlichen Verwendung dieser Variablen so nahe wie möglich zu kommen.
  • Das wantonale Deklarieren von Variablen in einem zu weiten Bereich weist häufig auf einen Entwickler hin, der OOP oder dessen Implementierung nicht ganz versteht. Das Erkennen von Variablen mit zu großem Umfang ist eine rote Fahne dafür, dass beim OOP -Ansatz wahrscheinlich etwas schief geht (entweder beim Entwickler im Allgemeinen oder bei der Codebasis im Besonderen).
  • (Kommentar von Kevin) Die Verwendung von Einheimischen zwingt Sie dazu, die Dinge in der richtigen Reihenfolge zu tun. Im ursprünglichen Code (Klassenvariable) könnten Sie passRequestToServiceClient() fälschlicherweise an den Anfang der Methode verschieben, und es würde trotzdem kompiliert. Bei Einheimischen könnten Sie diesen Fehler nur machen, wenn Sie eine nicht initialisierte Variable übergeben, was hoffentlich offensichtlich genug ist, dass Sie es nicht wirklich tun.

Trotz dieser Vorteile kann ich den ursprünglichen Entwickler immer noch nicht davon überzeugen, dass dieses Refactoring gerechtfertigt ist, da es den oben erwähnten Praktiken von Onkel Bob zu widersprechen scheint.

Und umgekehrt, gibt es Nachteile bei diesem Refactoring, die ich möglicherweise übersehen habe?

Das Problem hierbei ist, dass Ihr Argument für lokale Variablen gültig ist, Sie jedoch auch zusätzliche Änderungen vorgenommen haben, die nicht korrekt sind und dazu führen, dass Ihr vorgeschlagener Fix den Geruchstest nicht besteht.

Obwohl ich Ihren Vorschlag "keine Klassenvariable" verstehe und es einen Vorteil hat, haben Sie tatsächlich auch die Methoden selbst entfernt, und das ist ein ganz anderes Ballspiel. Die Methoden sollten erhalten bleiben, und stattdessen sollten Sie sie geändert haben, um ihren Wert zurückzugeben, anstatt ihn in einer Klassenvariablen zu speichern:

private byte[] getEncodedData() {
    return cryptoService.decryptRequest(encryptedRequest, byte[].class);
}

private EncryptionInfo getEncryptionInfo() {
    return cryptoService.getEncryptionInfoForDefaultClient();
}

// and so on...

Ich stimme dem zu, was Sie in der Methode process getan haben, aber Sie hätten die privaten Untermethoden aufrufen sollen, anstatt ihre Körper direkt auszuführen.

public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    checkNotNull(encryptedRequest);

    byte[] encodedData = getEncodedData();
    EncryptionInfo encryptionInfo = getEncryptionInfo();

    //and so on...

    return cryptoService.encryptResponse(payloadOfResponse);
}

Sie möchten diese zusätzliche Abstraktionsebene, insbesondere wenn Sie auf Methoden stoßen, die mehrmals wiederverwendet werden müssen. Auch wenn Sie Ihre Methoden derzeit nicht wiederverwenden , ist es immer noch eine gute Praxis, gegebenenfalls bereits Untermethoden zu erstellen, auch wenn dies nur die Lesbarkeit des Codes verbessert .

Unabhängig vom Argument der lokalen Variablen habe ich sofort festgestellt, dass Ihr Änderungsvorschlag erheblich weniger lesbar ist als das Original. Ich gebe zu, dass die mutwillige Verwendung von Klassenvariablen auch die Lesbarkeit des Codes beeinträchtigt, aber nicht auf den ersten Blick, wenn Sie die gesamte Logik in einer einzigen (jetzt langwierigen) Methode gestapelt haben.

169
Flater

Der ursprüngliche Code verwendet Mitgliedsvariablen wie Argumente. Wenn er sagt, die Anzahl der Argumente zu minimieren, meint er wirklich, die Datenmenge zu minimieren, die die Methoden benötigen, um zu funktionieren. Das Einfügen dieser Daten in Mitgliedsvariablen verbessert nichts.

79
Alex

Andere Antworten haben die Vorteile lokaler Variablen bereits perfekt erklärt. Es bleibt also nur dieser Teil Ihrer Frage:

Trotz dieser Vorteile kann ich den ursprünglichen Entwickler immer noch nicht davon überzeugen, dass dieses Refactoring gerechtfertigt ist, da es den oben erwähnten Praktiken von Onkel Bob zu widersprechen scheint.

Das sollte einfach sein. Zeigen Sie ihm einfach auf das folgende Zitat in Onkel Bobs Clean Code:

keine Nebenwirkungen haben

Nebenwirkungen sind Lügen. Ihre Funktion verspricht, eine Sache zu tun, aber sie tut auch andere versteckte Dinge. Manchmal werden unerwartete Änderungen an den Variablen der eigenen Klasse vorgenommen. Manchmal werden sie zu den Parametern gemacht, die an die Funktion übergeben werden, oder zu Systemglobalen. In beiden Fällen handelt es sich um falsche und schädliche Unwahrheiten, die häufig zu seltsamen zeitlichen Kopplungen und Ordnungsabhängigkeiten führen.

(Beispiel weggelassen)

Dieser Nebeneffekt erzeugt eine zeitliche Kopplung. Das heißt, checkPassword kann nur zu bestimmten Zeiten aufgerufen werden (mit anderen Worten, wenn es sicher ist, die Sitzung zu initialisieren). Wenn es nicht in der richtigen Reihenfolge aufgerufen wird, können Sitzungsdaten versehentlich verloren gehen. Zeitliche Kopplungen sind verwirrend, insbesondere wenn sie als Nebeneffekt verborgen sind. Wenn Sie eine zeitliche Kopplung haben müssen, sollten Sie dies im Namen der Funktion klarstellen. In diesem Fall könnten wir die Funktion checkPasswordAndInitializeSession umbenennen, obwohl dies sicherlich gegen "Do one thing" verstößt.

Das heißt, Onkel Bob sagt nicht nur, dass eine Funktion nur wenige Argumente enthalten sollte, er sagt auch, dass Funktionen nach Möglichkeit die Interaktion mit dem nicht lokalen Status vermeiden sollten.

47
meriton

"Es widerspricht dem, was jemandes Onkel denkt" ist NIE ein gutes Argument. NOCH NIE. Nimm keine Weisheit von Onkeln, denke selbst.

Allerdings sollten Instanzvariablen verwendet werden, um Informationen zu speichern, die tatsächlich dauerhaft oder semipermanent gespeichert werden müssen. Die Informationen hier sind nicht. Es ist sehr einfach, ohne die Instanzvariablen zu leben, damit sie gehen können.

Test: Schreiben Sie einen Dokumentationskommentar für jede Instanzvariable. Können Sie etwas schreiben, das nicht völlig sinnlos ist? Schreiben Sie einen Dokumentationskommentar an die vier Accessoren. Sie sind ebenso sinnlos.

Am schlimmsten ist es, wenn Sie Änderungen entschlüsseln, da Sie einen anderen cryptoService verwenden. Anstatt vier Codezeilen ändern zu müssen, müssen Sie vier Instanzvariablen durch unterschiedliche ersetzen, vier Getter durch unterschiedliche und vier Codezeilen ändern.

Aber natürlich ist die erste Version vorzuziehen, wenn Sie mit der Codezeile bezahlt werden. 31 Zeilen statt 11 Zeilen. Dreimal mehr Zeilen zum Schreiben und für immer beibehalten, zum Lesen beim Debuggen, zum Anpassen, wenn Änderungen erforderlich sind, zum Duplizieren, wenn Sie einen zweiten cryptoService unterstützen.

(Verpasste den wichtigen Punkt, dass Sie durch die Verwendung lokaler Variablen gezwungen sind, die Aufrufe in der richtigen Reihenfolge durchzuführen).

25
gnasher729

Was ist die objektive wissenschaftliche Begründung, um lokale Variablen gegenüber Instanzvariablen zu bevorzugen? Ich kann nicht ganz meinen Finger darauf legen. Meine Intuition sagt mir, dass versteckte Kopplungen schlecht sind und dass ein enger Bereich besser ist als ein breiter. Aber was ist die Wissenschaft, um dies zu unterstützen?

Instanzvariablen dienen zur Darstellung der Eigenschaften ihres Host-Objekts, nicht zur Darstellung von Eigenschaften, die für Berechnungsthreads spezifisch sind, die enger sind als das Objekt selbst. Einige der Gründe für eine solche Unterscheidung, die offenbar noch nicht behandelt wurden, betreffen Parallelität und Wiedereintritt. Wenn Methoden Daten austauschen, indem sie die Werte von Instanzvariablen festlegen, können zwei gleichzeitige Threads die Werte für diese Instanzvariablen leicht gegenseitig überfrachten, was zu zeitweiligen, schwer zu findenden Fehlern führt.

Selbst ein Thread allein kann auf Probleme in dieser Richtung stoßen, da ein hohes Risiko besteht, dass ein Datenaustauschmuster, das auf Instanzvariablen beruht, Methoden nicht wiedereintrittsfähig macht. Wenn dieselben Variablen zum Übertragen von Daten zwischen verschiedenen Methodenpaaren verwendet werden, besteht in ähnlicher Weise das Risiko, dass ein einzelner Thread, der selbst eine nicht rekursive Kette von Methodenaufrufen ausführt, auf Fehler stößt, die sich um unerwartete Änderungen der beteiligten Instanzvariablen drehen.

Um in einem solchen Szenario zuverlässig korrekte Ergebnisse zu erzielen, müssen Sie entweder separate Variablen verwenden, um zwischen jedem Methodenpaar zu kommunizieren, bei dem eines das andere aufruft, oder jede Methodenimplementierung muss alle Implementierungsdetails aller anderen berücksichtigen Methoden, die direkt oder indirekt aufgerufen werden. Dies ist spröde und skaliert schlecht.

13
John Bollinger

Wenn Sie nur process(...) diskutieren, ist das Beispiel Ihrer Kollegen im Sinne der Geschäftslogik weitaus besser lesbar. Umgekehrt benötigt Ihr Gegenbeispiel mehr als einen flüchtigen Blick, um eine Bedeutung zu extrahieren.

Trotzdem ist sauberer Code sowohl lesbar als auch von guter Qualität - das Herausschieben des lokalen Staates in einen globaleren Raum ist nur eine hochrangige Versammlung, also eine Null für Qualität.

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  public EncryptedResponse process(EncryptedRequest request) {
    checkNotNull(encryptedRequest);

    return encryptResponse
      (routeTo
         ( destination()
         , requestData(request)
         , destinationEncryption()
         )
      );
  }

  private byte[] requestData(EncryptedRequest encryptedRequest) {
    return cryptoService.decryptRequest(encryptedRequest, byte[].class);
  }

  private EncryptionInfo destinationEncryption() {
    return cryptoService.getEncryptionInfoForDefaultClient();
  }

  private URI destination() {
    return router.getDestination().getUri();
  }

  private EncryptedObject routeTo(URI destinationURI, byte[] encodedData, EncryptionInfo encryptionInfo) {
    return serviceClient.handle(destinationURI, encodedData, encryptionInfo);
  }

  private void encryptResponse(EncryptedObject payloadOfResponse) {
    return cryptoService.encryptResponse(payloadOfResponse);
  }
}

Dies ist eine Wiedergabe, die die Notwendigkeit von Variablen in jedem Bereich beseitigt. Ja, der Compiler generiert sie, aber der wichtige Teil ist, dass er dies steuert, damit der Code effizient ist. Während auch relativ gut lesbar.

Nur ein Punkt zur Benennung. Sie möchten den kürzesten Namen, der aussagekräftig ist und die bereits verfügbaren Informationen erweitert. dh. destinationURI, der 'URI' ist bereits unter der Typensignatur bekannt.

9
Kain0_0

Ich würde nur diese Variablen und privaten Methoden insgesamt entfernen. Hier ist mein Refactor:

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    return cryptoService.encryptResponse(
        serviceClient.handle(router.getDestination().getUri(),
        cryptoService.decryptRequest(encryptedRequest, byte[].class),
        cryptoService.getEncryptionInfoForDefaultClient()));
  }
}

Für private Verfahren, z. router.getDestination().getUri() ist klarer und lesbarer als getDestinationURI(). Ich würde das sogar nur wiederholen, wenn ich dieselbe Zeile zweimal in derselben Klasse verwende. Anders ausgedrückt: Wenn eine getDestinationURI() benötigt wird, gehört sie wahrscheinlich in eine andere Klasse, nicht in die Klasse SomeBusinessProcess.

Bei Variablen und Eigenschaften müssen sie häufig Werte enthalten, die später verwendet werden sollen. Wenn die Klasse keine öffentliche Schnittstelle für die Eigenschaften hat, sollten sie wahrscheinlich keine Eigenschaften sein. Die schlechteste Art der Verwendung von Klasseneigenschaften ist wahrscheinlich die Übergabe von Werten zwischen privaten Methoden über Nebenwirkungen.

Auf jeden Fall muss die Klasse nur process() ausführen, und dann wird das Objekt weggeworfen. Es ist nicht erforderlich, einen Status im Speicher zu behalten. Ein weiteres Refactor-Potenzial wäre, den CryptoService aus dieser Klasse herauszunehmen.

Basierend auf Kommentaren möchte ich hinzufügen, dass diese Antwort auf der Praxis basiert. In der Tat würde ich bei der Codeüberprüfung als erstes die Klasse umgestalten und die Verschlüsselungs-/Entschlüsselungsarbeit verschieben. Sobald das erledigt ist, würde ich fragen, ob die Methoden und Variablen benötigt werden, ob sie richtig benannt sind und so weiter. Der endgültige Code wird wahrscheinlich näher daran sein:

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;

  public Response process(Request request) {
    return serviceClient.handle(router.getDestination().getUri());
  }
}

Mit dem obigen Code glaube ich nicht, dass es eines weiteren Refactors bedarf. Wie bei den Regeln denke ich, dass es Erfahrung braucht, um zu wissen, wann und wann man sie nicht anwendet. Regeln sind keine Theorien, die nachweislich in allen Situationen funktionieren.

Die Codeüberprüfung hat dagegen einen echten Einfluss darauf, wie lange es dauert, bis ein Code verstrichen ist. Mein Trick ist, weniger Code zu haben und es leicht verständlich zu machen. Ein Variablenname kann ein Diskussionspunkt sein, wenn ich ihn entfernen kann, müssten Rezensenten nicht einmal darüber nachdenken.

7
imel96

Flaters Antwort deckt Fragen des Scoping recht gut ab, aber ich denke, dass es auch hier ein anderes Problem gibt.

Beachten Sie, dass es einen Unterschied zwischen einer Funktion gibt, die Daten verarbeitet Und einer Funktion, die einfach auf Daten zugreift.

Ersteres führt die eigentliche Geschäftslogik aus, während letzteres die Eingabe spart und möglicherweise die Sicherheit erhöht, indem eine einfachere und wiederverwendbarere Schnittstelle hinzugefügt wird.

In diesem Fall scheinen die Datenzugriffsfunktionen die Eingabe nicht zu speichern und werden nirgendwo wiederverwendet (oder es gibt andere Probleme beim Entfernen). Diese Funktionen sollten also einfach nicht existieren.

Indem wir nur die Geschäftslogik in benannten Funktionen behalten, erhalten wir das Beste aus beiden Welten (irgendwo zwischen Flaters Antwort und imel96s Antwort ):

public EncryptedResponse process(EncryptedRequest encryptedRequest) {

    byte[] requestData = decryptRequest(encryptedRequest);
    EncryptedObject responseData = handleRequest(router.getDestination().getUri(), requestData, cryptoService.getEncryptionInfoForDefaultClient());
    EncryptedResponse response = encryptResponse(responseData);

    return response;
}

// define: decryptRequest(), handleRequest(), encryptResponse()
4
user673679

Das Erste und Wichtigste: Onkel Bob scheint manchmal wie ein Prediger zu sein, gibt jedoch an, dass es Ausnahmen von seinen Regeln gibt.

Die gesamte Idee von Clean Code besteht darin, die Lesbarkeit zu verbessern und Fehler zu vermeiden. Es gibt mehrere Regeln, die sich gegenseitig verletzen.

Sein Argument zu Funktionen ist, dass niladische Funktionen am besten sind, jedoch bis zu drei Parameter akzeptabel sind. Ich persönlich denke, dass 4 auch ok sind.

Wenn Instanzvariablen verwendet werden, sollten sie eine kohärente Klasse bilden. Das heißt, die Variablen sollten in vielen, wenn nicht allen nicht statischen Methoden verwendet werden.

Variablen, die an vielen Stellen der Klasse nicht verwendet werden, sollten verschoben werden.

Ich würde weder die ursprüngliche noch die überarbeitete Version als optimal betrachten, und @Flater hat bereits sehr gut angegeben, was mit Rückgabewerten getan werden kann. Es verbessert die Lesbarkeit und reduziert Fehler bei der Verwendung von Rückgabewerten.

2
kap

Lokale Variablen reduzieren den Umfang und schränken daher die Verwendungsmöglichkeiten der Variablen ein. Dadurch werden bestimmte Fehlerklassen vermieden und die Lesbarkeit verbessert.

Instanzvariablen reduzieren die Art und Weise, wie die Funktion aufgerufen werden kann, wodurch auch bestimmte Fehlerklassen reduziert und die Lesbarkeit verbessert werden.

Zu sagen, dass einer richtig und der andere falsch ist, kann in einem bestimmten Fall durchaus eine gültige Schlussfolgerung sein, aber als allgemeiner Ratschlag ...

TL; DR: Ich denke, der Grund, warum Sie zu viel Eifer riechen, ist, dass es zu viel Eifer gibt.

1
drjpizzle

Beide Dinge tun dasselbe und die Leistungsunterschiede sind nicht wahrnehmbar, daher glaube ich nicht, dass es ein wissenschaftliches Argument gibt. Es kommt dann auf subjektive Vorlieben an.

Und auch ich mag Ihren Weg besser als den Ihres Kollegen. Warum? Weil ich denke, es ist einfacher zu lesen und zu verstehen, trotz der Aussagen einiger Buchautoren.

Beide Wege erreichen dasselbe, aber sein Weg ist weiter verbreitet. Um diesen Code zu lesen, müssen Sie zwischen mehreren Funktionen und Elementvariablen hin und her wechseln. Es ist nicht alles an einem Ort zusammengefasst, Sie müssen sich an alles in Ihrem Kopf erinnern, um es zu verstehen. Es ist eine viel größere kognitive Belastung.

Im Gegensatz dazu packt Ihr Ansatz alles viel dichter, aber nicht, um es undurchdringlich zu machen. Sie lesen es einfach Zeile für Zeile und müssen sich nicht so viel merken, um es zu verstehen.

Wenn er jedoch verwendet ist, um Code so zu gestalten, kann ich mir vorstellen, dass es für ihn umgekehrt sein könnte.

0
Vilx-

Trotz der Tatsache, dass Methoden, die mit get ... beginnen, nicht ungültig werden sollten, wird in der ersten Lösung die Trennung der Abstraktionsebenen innerhalb der Methoden angegeben. Obwohl die zweite Lösung einen größeren Umfang hat, ist es immer noch schwieriger zu überlegen, was in der Methode vor sich geht. Die Zuweisung lokaler Variablen wird hier nicht benötigt. Ich würde die Methodennamen behalten und den Code so umgestalten:

public class SomeBusinessProcess {
  @Inject private Router router;
  @Inject private ServiceClient serviceClient;
  @Inject private CryptoService cryptoService;

  public EncryptedResponse process(EncryptedRequest encryptedRequest) {
    checkNotNull(encryptedRequest);

    return getEncryptedResponse(
            passRequestToServiceClient(getDestinationURI(), getEncodedData(encryptedRequest) getEncryptionInfo())
        );
  }

  private EncryptedResponse getEncryptedResponse(EncryptedObject encryptedObject) {
    return cryptoService.encryptResponse(encryptedObject);
  }

  private byte[] getEncodedData(EncryptedRequest encryptedRequest) {
    return cryptoService.decryptRequest(encryptedRequest, byte[].class);
  }

  private EncryptionInfo getEncryptionInfo() {
    return cryptoService.getEncryptionInfoForDefaultClient();
  }

  private URI getDestinationURI() {
    return router.getDestination().getUri();
  }

  private EncryptedObject passRequestToServiceClient(URI destinationURI, byte[] encodedData, EncryptionInfo encryptionInfo) {
    return serviceClient.handle(destinationURI, encodedData, encryptionInfo);
  }
}
0
Roman Weis