Какой подход сохранить свойство модели лучше?

У меня есть модель Order (модель, как она выглядит в CakePhp), которая имеет статус свойства. Это свойство изменилось, пока заказ прошел стадии обработки. В настоящее время изменение статуса работает следующим образом:

У меня есть связанная модель OrderStatus, где у меня есть набор возможных статусов, например

<p> в модели заказа У меня есть способ изменить статус:</p> <code> <p> и когда мне нужно изменить его где-нибудь в контроллере, или другую модель, я просто назову ее так:</p> <pre class="prettyprint linenums">&lt;!--?php $Order---&gt;changeStatus($id, OrderStatus::PAID);</pre> <p> Пока все хорошо работает с этим решением, но теперь я думаю, насколько правильным этот подход. Что делать, если завтра я решит сделать некоторые дополнительные действия для изменения определенного статуса, поэтому мне нужно добавить дополнительную логику и расширить метод changeStatus. Также мне не очень нравится, что мне приходится использовать константы OrderStatus везде, где мне нужно изменить статус заказа, поэтому он распространяется по всему коду.</p> <p> Неправильно добавить отдельные методы для установки каждого нового статуса, использовать константы OrderStatus в этих методах и поместить туда всю связанную логику и изменить состояния вне модели заказа таким образом, как:</p> <pre class="prettyprint linenums">&lt;!--?php $Order---&gt;makePaid($id); // and $Order-&gt;makeProcessed($id);</pre> <p> Какой из них лучше от принципов ООП и лучшая практика, или, может быть, есть еще одно лучшее решение.</p>
3 ответа

Прежде всего, что вы и большинство из "MVC" (обратите внимание, что это в кавычках, потому что они на самом деле не MVC, а больше похожи на попытку имитировать шаблон, но они не являются) фреймворки call "model" - это сущность с бизнес-логикой в одной. В большинстве случаев они используют шаблон Active Record, чтобы иметь возможность представлять ссылки в БД более абстрактным образом.

Что касается вашего вопроса, в первую очередь, это неправильно с точки зрения "контроллера" (в кавычках снова, потому что это не совсем контроллер, поскольку он делает гораздо больше), чтобы быть вовлеченным в эту проблему с самой сущностью. Гораздо лучше, что есть слой "Сервис", который абстрагирует то, что вы хотите сделать, которое вызывается "контроллером", а сам "Сервис" знает, как обрабатывать эти запросы. Я пытаюсь сказать, что контроллер только передает события.

В вашем случае должно быть что-то вроде OrdersService которое поддерживает логику заказов. Например: создание нового, оплата такого заказа и т.д. Контроллер создает экземпляр OrdersService и вызывает $ordersService->createOrder($requiredData) или $ordersService->processOrder($id). Затем OrdersService с другой стороны, называет "модель" заказа для обработки таких событий отдельно. Чем больше разделение логики у вас в разных классах, тем лучше. Обычно многие люди стараются следовать логике рамок и в конечном итоге сталкиваются с массивными классами Бога, в которых слишком много логики.

Пожалуйста, подумайте о том, чтобы прочитать SOLID Principles and Separation Of Concerns, если вы хотите начать использовать лучшие методы ООП в целом.


В "Чистом коде" Роберт К. Мартин советовал, что чем меньше аргументов, тем лучше. Лучше создать выделенный метод для данного действия, чем общий, с большим количеством аргументов. Таким образом, ваш код будет более выразительным для читателей.

В вашем примере, если вы создаете выделенный метод для каждого действия, которое изменяет статус, изменение самого состояния станет деталью реализации объекта заказа и не будет отображаться вне объекта. Это большое преимущество, потому что вы можете изменить его, а упорядочивающие классы не нуждаются в каких-либо изменениях.


Я предлагаю, чтобы объект Order должен представлять один заказ (один id) с методами, относящимися к операциям, которые могут выполняться в заказе. Это должно иметь смысл для проблемы, которую ваше приложение пытается решить. Поэтому, если заказ должен быть оплачен, почему бы не получить метод pay(); побочным эффектом которого может быть установка правильного текущего состояния. Аналогично для начала и процесса.

class Order {

 private $id;
 private $currentStatus;

 //other methods...

 public function pay(Money $payment) {
 //handle payment etc.
 $this->currentStatus = OrderStatus::PAID;
 }

 public function start() {
 //do business logic related to starting an order.
 $this->currentStatus = OrderStatus::STARTED;
 }

 public function process() {
 //process an order
 $this->currentStatus = OrderStatus::PROCESSED;
 }

}

licensed under cc by-sa 3.0 with attribution.