Java >> Java-zelfstudie >  >> Java

Niet parseren, maar objecten parseren

De traditionele manier om objectgeoriënteerde back-end met een extern systeem te integreren, is door middel van gegevensoverdrachtobjecten, die worden geserialiseerd in JSON voordat ze uitgaan en gedeserialiseerd wanneer ze terugkomen. Deze manier is even populair als verkeerd. Het serialisatiegedeelte moet worden vervangen door printers, wat ik eerder heb uitgelegd. Hier is mijn kijk op deserialisatie, die moet worden gedaan door - raad eens - objecten.






La science des rêves (2006) door Michel Gondry

Stel dat er een back-end-toegangspunt is dat een nieuw boek in de bibliotheek moet registreren en aankomt in JSON:

{
  "title": "Object Thinking",
  "isbn: "0735619654",
  "author: "David West"
}

Er is ook een object van klasse Library , die een object van het type Book . verwacht te geven aan zijn methode register() :

class Library {
  public void register(Book book) {
    // Create a new record in the database
  }
}

Zeg ook, typ Book heeft een eenvoudige methode isbn() :

interface Book {
  String isbn();
}

Nu, hier is het HTTP-toegangspunt (ik gebruik Takes en Cactoos), dat een POST multipart/form-data accepteert het boek aanvragen en registreren in de bibliotheek:

public class TkUpload implements Take {
  private final Library library;
  @Override
  public Response act(Request req) {
    String body = new RqPrint(
      new RqMtSmart(new RqMtBase(req)).single("book")
    ).printBody();
    JsonObject json = Json.createReader(
      new InputStreamOf(body)
    ).readObject();
    Book book = new BookDTO();
    book.setIsbn(json.getString("isbn"));
    library.register(book);
  }
}

Wat is hier mis mee? Nou ja, een paar dingen.

Ten eerste is het niet herbruikbaar. Als we iets soortgelijks op een andere plaats nodig zouden hebben, zouden we deze HTTP-verwerking en JSON-parsing opnieuw moeten schrijven.

Ten tweede zijn foutafhandeling en validatie ook niet herbruikbaar. Als we het toevoegen aan de bovenstaande methode, zullen we het overal moeten kopiëren. Natuurlijk kan de DTO het inkapselen, maar daar zijn DTO's meestal niet voor.

Ten derde is de bovenstaande code nogal procedureel en heeft veel temporele koppeling.

Een beter ontwerp zou zijn om deze ontleding te verbergen in een nieuwe klasse JsonBook :

class JsonBook implements Book {
  private final String json;
  JsonBook(String body) {
    this.json = body;
  }
  @Override
  public String isbn() {
    return Json.createReader(
      new InputStreamOf(body)
    ).readObject().getString("isbn");
  }
}

Het RESTful-toegangspunt ziet er dan als volgt uit:

public class TkUpload implements Take {
  private final Library library;
  @Override
  public Response act(Request req) {
    library.register(
      new JsonBook(
        new RqPrint(
          new RqMtSmart(new RqMtBase(req)).single("book")
        ).printBody()
      )
    );
  }
}

Is dat niet eleganter?

Hier zijn enkele voorbeelden van mijn projecten:RqUser van zerocracy/farm en RqUser van yegor256/jare.

Zoals je kunt zien aan de hand van de bovenstaande voorbeelden, kunnen we soms implements . niet gebruiken omdat sommige primitieven in Java geen interfaces zijn, maar final klassen:String is een "perfect" voorbeeld. Daarom moet ik dit doen:

class RqUser implements Scalar<String> {
  @Override
  public String value() {
    // Parsing happens here and returns String
  }
}

Maar afgezien daarvan demonstreren deze voorbeelden perfect het hierboven voorgestelde principe van het "parseren van objecten".

Java-tag