[GO] Wickeln Sie das Validierungsziel ein und kapseln Sie es ein, um Komplikationen zu vermeiden

[Ergänzung] Wenn ich darüber nachdenke, war es kein Dekorateur, weil ich mich nicht mit vorhandenen Methoden angelegt habe. Dies ist der Name, bei dem der Mustername nicht plötzlich herauskommt. Ist es nur Fassade?

TL;DR

Durch die separate Implementierung der Wrapper-Klasse für "Validation" und der Wrapper-Klasse für "Creation" wird die Schnittstelle für jede Verantwortung angegeben.

Wann ist es wirksam?

Wenn eine Validierungslogik getrennt von der Validierung mithilfe der Funktion des Frameworks erforderlich ist. Insbesondere bei der Implementierung eines Systems wie OpenID Connect, bei dem eine Fehlerantwort per Umleitung zurückgegeben werden muss, die von der vom Framework generierten Fehlerantwort nicht verarbeitet werden kann.

Der Einfachheit halber wird hier die Logik als Beispiel für die OpenID Connect-Fehlerantwort verwendet. Sie gilt jedoch für alle Systeme, in denen eine komplexe Validierung implementiert werden muss.

Was möchten Sie tun

Wenn beim Konvertieren eines Anforderungsparameters in ein Domänenobjekt die Validierung und Generierung von Domänenobjekten basierend auf einem Anforderungsobjekt durchgeführt wird, verschlechtert sich die Lesbarkeit des Codes. Daher möchte ich dies vermeiden.

In OpenID Connect ist es beispielsweise häufig der Fall, dass die Codemenge im Volume nur durch Validieren der Autorisierungsanforderung ziemlich groß ist. Aus Gründen der Leistung ist es wünschenswert, das während der Validierung generierte Objekt im Kontext zu belassen. Außerdem muss das Muster "Eigentlich war es eine OAuth2-Anforderung anstelle von OpenID Connect" berücksichtigt werden, sodass die Anzahl der Verzweigungen in der Validierungslogik lächerlich ist.

Wenn möglich, möchte ich für jeden Verzweigungsfluss eine Anforderungsobjektklasse generieren und eine Validierungslogik-Verzweigung mit Polymorphismus realisieren, um keine Testfall-Explosion zu verursachen.

In der Realität gibt es jedoch viele gängige Prozesse, unabhängig vom Ablauf, und Methoden wie "request.isImplicitFlow ()" werden von überall aufgerufen, sodass sie im Anforderungsobjekt implementiert werden.

Die oben genannten Methoden werden nur während der Validierung verwendet. Dies liegt daran, dass Flow nach der Konvertierung in ein Domänenobjekt statisch ist und wahrscheinlich eine Klasse wie "ImplicitFlowHandler" die Arbeit erledigen sollte.

Zur Erinnerung, es geht nicht nur um OpenID Connect

Wenn Sie also eine Wrapper-Klasse für die Validierung vorbereiten und die Delegierungsmethode implementieren, wird die Methode nicht im Anforderungsobjekt selbst implementiert, sodass die Sichtbarkeit des Codes besser ist.

Beispielcode

Da die Controller-Schicht HTTP-Anforderungsparameter empfängt, lautet das Feld immer "String".

package jp.hoge.openidconnect.authorization;
import lombok.Getter;

//Objekt anfordern
// (Objekt zum Binden von HTTP-Anforderungsparametern)
@Getter //Getter soll definiert werden
public class AuthorizationRequest {
  private String responseType;
  private String clientId;
  private String scope;
}
package jp.hoge.openidconnect.authorization.validation;

import jp.hoge.openidconnect.core.ResponseType;

//Wrapper-Klasse zur Validierung.Erben Sie die Wrapping-Klasse.
//Die Sichtbarkeit ist immer die Standardeinstellung des Pakets. 
class RequestWrapperForValidation extends AuthorizationRequest {

  private final AuthorizationRequest rawRequest;
  
  private ResponseType responseType = null;

  //Die Sichtbarkeit des Konstruktors ist ebenfalls paketiert
  RequestWrapperForValidation(final AuthorizationRequest rawRequest) {
    this.rawRequest = rawRequest;
  }

  //Eine Methode, die nur in der Validierungsschicht verwendet wird.
  //Das eigentliche OpenID Connect ist komplizierter, aber es ist kompliziert, so dass es ein grobes Bild ist
  boolean isImplicitFlow() {
    if (rawRequest.getScope().contains("openid")) {
      return _getResponseType().contains(ResponseType.ID_TOKEN);
    } else {
      return _getResponseType().contains(ResponseType.TOKEN);
    }
  }

  //Methode zum Konvertieren in ein Domänenobjekt nur einmal
  //Sie können im Validierungsprozess mehrmals auf das hier generierte Objekt verweisen..
  //Allerdings Thread-Machen Sie deutlich, dass es nicht sicher ist.
  private ResponseType _getResponseType() {
    if (this.responseType == null) {
      this.responseType = ResponseType.parse(rawRequest.getResponseType());
    }
    return this.responseType;
  }

  //Delegierungsmethode für die Wrapping-Klasse
  public String getResponseType() {
    return rawRequest.getResponseType();
  }
  // ...Danach implementieren wir die Delegierungsmethode
}

Wenn Sie es so implementieren (unabhängig davon, ob der Code gut oder schlecht ist), können Sie die Validierungsmethode aus demselben Paket (Validierungsschicht) verwenden, sie sieht jedoch genauso aus wie das ursprüngliche Objekt aus anderen Schichten.

Bei Webspezifikationen wie OpenID Connect spielt es keine Rolle, ob sich das Anforderungsobjekt in der Domänenschicht befindet. Bei gelegentlicher Verwendung wird jedoch die Schnittstelle des Anforderungsobjekts anstelle des Anforderungsobjekts umschlossen. Andernfalls verweist die Domänenschicht auf die Klasse der Controller-Schicht, dies ist also NG.

Wie bei der Validierung hilft auch das Vorbereiten einer Wrapper-Klasse während der Erstellung dabei, zu verhindern, dass die Antikorruptionsschicht aufgebläht wird. In diesem Fall ist es jedoch besser, es nur mit einem Builder-Muster zu implementieren.

public class AuthorizationModelBuilder {
  private final AuthorizationRequest rawRequest;

  public AuthorizationModel toDomainModel() {
    // ...Konvertierungsprozess zum Domänenmodell
  }
}

Es war ein Fehler, OpenID Connect zu zitieren. Das Domänenwissen war zu speziell

Weitere Hinweise

Es geht nicht nur um Validierung. Für Ebenen und Pakete mit unterschiedlichen Verantwortlichkeiten ist es besser, umschlossene Objekte zu verwenden, um die Benutzeroberfläche und die Verwendung zu verdeutlichen und die Lesbarkeit zu verbessern. Natürlich sind die Implementierungskosten hoch, seien Sie sich also des Kompromisses bewusst.

Recommended Posts

Wickeln Sie das Validierungsziel ein und kapseln Sie es ein, um Komplikationen zu vermeiden
Python-Memorandum: Lesen Sie den Text und bearbeiten Sie den Dateinamen, während Sie die Zieldatei kopieren
Konvertierung des Koordinatensystems in ECEF und Geodätik
Lassen Sie uns experimentieren und Beweise hinterlassen, um die Spezifikationen zu bestimmen.