Хотя в приведенном ниже коде используется простая покупка одного элемента на сайте электронной коммерции, мой общий вопрос заключается в обновлении всех членов данных, чтобы все время сохранять данные объекта в действительном состоянии.
Я нашел «последовательность» и «состояние зла» как соответствующие фразы, обсуждаемые здесь: 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();
Есть ли недостатки, или, может быть, лучшие способы сделать это?
Это повторяющаяся проблема в реальных приложениях, поддерживаемых реляционной базой данных, и если вы не используете хранимые процедуры, чтобы перенести всю проверку в базу данных. Я думаю, что хранилище данных должно просто хранить данные, а код должен выполнять всю работу по поддержанию состояния во время выполнения.
РЕДАКТИРОВАТЬ: это связанный вопрос, но он не имеет рекомендации передового опыта в отношении одной большой функции для поддержания действительного состояния: /programming/1122346/c-sharp-object-oriented-design-maintenance- действует объектно-состояние
РЕДАКТИРОВАТЬ 2: Хотя ответ @ eignesheep является лучшим, этот ответ - /software//a/148109/208591 - это то, что заполняет грань между ответом @ eigensheep и тем, что я хотел знать - код должен только обрабатываться, и глобальное состояние должно быть заменено передачей состояния с поддержкой DI между объектами.
источник
Ответы:
При прочих равных вы должны выразить свои инварианты в коде. В этом случае у вас есть инвариант
Чтобы выразить это в своем коде, удалите переменную налогового члена и замените getTaxAmt () на
Вы должны сделать что-то похожее, чтобы избавиться от переменной общей стоимости.
Выражение ваших инвариантов в вашем коде может помочь избежать ошибок. В исходном коде общая стоимость неверна, если проверяется перед вызовом setPrice или setShipping.
источник
getTotalCost()
вызовыgetTaxAmt()
и так далее. Это означает, что мы храним только не рассчитанные вещи . Двигаемся ли мы немного к функциональному программированию? Это также усложняет хранение вычисляемых объектов в таблицах для быстрого доступа ... Требуется эксперимент!Конечно. Этот метод полагается на то, что все всегда помнят что-то сделать. Любой метод, опирающийся на всех и всегда, иногда обречен на провал .
Одним из способов избежать бремени запоминания церемонии является вычисление свойств объекта, которые по мере необходимости зависят от других свойств, как предположил @eigensheep.
Другой способ - сделать элемент корзины неизменным и рассчитать его в конструкторе / фабричном методе. Обычно вы используете метод «Рассчитать по мере необходимости», даже если вы сделали объект неизменным. Но если расчет занимает слишком много времени и будет прочитан много-много раз; Вы можете выбрать опцию «Рассчитать при создании».
Вы должны спросить себя; Имеет ли смысл корзина без цены? Может ли цена товара измениться? После того, как это создано? После того, как его налог рассчитывается? и т. д. Может быть, вы должны сделать
CartItem
неизменную цену и доставку в конструкторе:Имеет ли смысл корзина без корзины, к которой она принадлежит?
Если нет, я бы ожидал
$cart->addItem(100, 20)
вместо этого.источник