Rolf B: Frage bzgl. OOP und einem Klassen Diagramm

Beitrag lesen

Hallo ebody,

mach nicht zu viel an einer Stelle. Du kannst die Datenbeschaffung im Konstruktor anstoßen, aber nicht durchführen, weil sie asynchron laufen muss.

class SpreadsheetReader {
   constructor(url) {
      // validiere url

      const fetchPromise = fetch(url, options)
                .then(response => {
                   if (!response.ok)
                      throw new Error(`HTTP error! status: ${response.status}`);
                   return response.json()
                })
                .then(json => new SpreadsheetData(json));

      Object.defineProperty(this, "complete", { value: fetchPromise, writable:false; });
   }
}

// Verwendung
const data = await (new SpreadsheetReader("https://google/bla/blub?alt=json")).complete;

// oder
(new SpreadsheetReader("https://google/bla/blub?alt=json"))
.complete.then(data => {
   // Verarbeiten
});

Der Konstruktor löst den Fetch-Request aus und legt das Promise für die Antwort in ein Property, das als readonly angelegt wird. Das ist die bessere Alternative zu einer getter-Methode, wenn Du keinen privaten Schreibzugriff brauchst.

Beachte, dass der await nicht auf das Konstruktorergebnis zielt, sondern auf das complete-Property, wo das Promise drinsteckt. Wenn das Ganze nicht in einer async-Funktion steckt, ist ein .then-Callback vermutlich einfacher als await.

Die Übergabe von json an den SpreadsheetData-Konstruktor könnte man weiter aufteilen. Man könnte durchaus sagen, dass die Konvertierung eines json-Strings in ein SpreadsheetData-Objekt nicht nach SpreadsheetData gehört. Und auch nicht in die Datenbeschaffung. Dafür könnte man eine Klasse SpreadsheetDataBuilder schreiben, die das json bekommt und ein SpreadsheetData Objekt liefert. Ihre Arbeit kann sie auf etliche kleine Methoden verteilen, die man dann separat mit Unit Tests absichern kann. Guck nicht so groß. Du fragtest nach OOP Best Practices. Kleinteilige Klassen und Unit Tests gehören dazu.

Ob Du den Reader unbedingt als Klasse implementieren musst, ist fraglich. Das Ding tut seinen Job nur im Konstruktor vermutlich könntest Du den auch als Funktion readGoogleSpreadsheet(url) implementieren. Entweder global, oder als Methode irgendeiner geeigneten Klasse.

Wenn Du unbedingt jquery-Ajax verwenden willst, dann kannst Du immer noch mit Promises arbeiten. $.ajax() liefert ein jQuery-Deferred Objekt zurück, das sich wie ein Promise verhält und demzufolge auch zu await kompatibel sein sollte.

$.ajax({ url: '...', type: 'json', ... })
.then(jsondata => (new SpreadsheetDataBuilder()).buildFromJson(jsondata))

Die Kleinteiligkeit schafft nicht unbedingt bessere Lesbarkeit. Da muss man gut aufpassen. Was sie schafft, ist Testbarkeit. Je kleiner die Bausteine, desto besser kannst Du jeden für sich in Isolation testen.

Robert C. Martin - Clean Code

Rolf

--
sumpsi - posui - obstruxi