Obwohl im folgenden Code ein einfacher Kauf eines einzelnen Artikels auf einer E-Commerce-Website verwendet wird, geht es bei meiner allgemeinen Frage darum, alle Datenelemente zu aktualisieren, um die Daten eines Objekts jederzeit in einem gültigen Zustand zu halten.
Ich fand "Konsistenz" und "Zustand ist böse" als relevante Ausdrücke, die hier besprochen wurden: https://en.wikibooks.org/wiki/Object_Oriented_Programming#.22State.22_is_Evil.21
<?php
class CartItem {
private $price = 0;
private $shipping = 5; // default
private $tax = 0;
private $taxPC = 5; // fixed
private $totalCost = 0;
/* private function to update all relevant data members */
private function updateAllDataMembers() {
$this->tax = $this->taxPC * 0.01 * $this->price;
$this->totalCost = $this->price + $this->shipping + $this->tax;
}
public function setPrice($price) {
$this->price = $price;
$this->updateAllDataMembers(); /* data is now in valid state */
}
public function setShipping($shipping) {
$this->shipping = $shipping;
$this->updateAllDataMembers(); /* call this in every setter */
}
public function getPrice() {
return $this->price;
}
public function getTaxAmt() {
return $this->tax;
}
public function getShipping() {
return $this->shipping;
}
public function getTotalCost() {
return $this->totalCost;
}
}
$i = new CartItem();
$i->setPrice(100);
$i->setShipping(20);
echo "Price = ".$i->getPrice().
"<br>Shipping = ".$i->getShipping().
"<br>Tax = ".$i->getTaxAmt().
"<br>Total Cost = ".$i->getTotalCost();
Irgendwelche Nachteile oder vielleicht bessere Möglichkeiten, dies zu tun?
Dies ist ein immer wiederkehrendes Problem in realen Anwendungen, die von einer relationalen Datenbank unterstützt werden, und wenn Sie gespeicherte Prozeduren nicht ausgiebig verwenden, um die gesamte Validierung in die Datenbank zu übertragen. Ich denke, dass der Datenspeicher nur Daten speichern sollte, während der Code die gesamte Arbeit zur Aufrechterhaltung des Laufzeitstatus erledigen sollte.
BEARBEITEN: Dies ist eine verwandte Frage, es gibt jedoch keine Best-Practice-Empfehlung für eine einzelne große Funktion, um den gültigen Status beizubehalten: /programming/1122346/c-sharp-object-oriented-design-maintaining- Gültiger Objektstatus
EDIT2: Obwohl die Antwort von @ eignesheep die beste ist, füllt diese Antwort - /software//a/148109/208591 - die Grenzen zwischen der Antwort von @ eigensheep und dem, was ich wissen wollte - Code sollte nur verarbeitet werden. Der globale Status sollte durch die DI-aktivierte Statusübergabe zwischen Objekten ersetzt werden.
quelle
Antworten:
Wenn alles andere gleich ist, sollten Sie Ihre Invarianten in Code ausdrücken. In diesem Fall haben Sie die Invariante
Um dies in Ihrem Code auszudrücken, entfernen Sie die Steuervariable und ersetzen Sie getTaxAmt () durch
Sie sollten etwas Ähnliches tun, um die Variable "Gesamtkostenelement" zu entfernen.
Das Ausdrücken Ihrer Invarianten in Ihrem Code kann helfen, Fehler zu vermeiden. Im Originalcode sind die Gesamtkosten falsch, wenn sie vor dem Aufruf von setPrice oder setShipping überprüft werden.
quelle
getTotalCost()
AufrufegetTaxAmt()
und so weiter. Das heißt, wir speichern immer nur nicht kalkulierte Dinge . Bewegen wir uns ein bisschen in Richtung funktionale Programmierung? Dies erschwert auch die Speicherung von berechneten Entitäten in Tabellen für den schnellen Zugriff.Sicher. Diese Methode beruht darauf, dass sich jeder daran erinnert , etwas zu tun. Jede Methode, die sich auf alle stützt, ist manchmal zum Scheitern verurteilt .
Eine Möglichkeit, die Last des Erinnerns an die Zeremonie zu vermeiden, besteht darin, die Eigenschaften des Objekts zu berechnen, die nach Bedarf von anderen Eigenschaften abhängen, wie von @eigensheep vorgeschlagen.
Zum anderen wird der Warenkorbartikel unveränderlich gemacht und im Konstruktor / in der Factory-Methode berechnet. Normalerweise würden Sie die Methode "Berechnen nach Bedarf" verwenden, selbst wenn Sie das Objekt unveränderlich machen würden. Aber wenn die Berechnung zu zeitaufwändig ist und viele, viele Male gelesen werden würde; Sie können die Option "Beim Erstellen berechnen" wählen.
Sie sollten sich fragen; Ist ein Einkaufswagenartikel ohne Preis sinnvoll? Kann sich der Preis eines Artikels ändern? Nachdem es erstellt wurde? Nach seiner Steuer berechnet? etc Vielleicht solltest du
CartItem
unveränderlichen und assig Preis und Versand im Konstruktor machen:Ist ein Warenkorbartikel ohne den dazugehörigen Warenkorb sinnvoll?
Wenn nicht, würde ich
$cart->addItem(100, 20)
stattdessen erwarten .quelle