для моего вопроса о том, как использовать ООП выгодным образом, я предполагаю в качестве примера КОРЗИЮ, к которой ее владелец (Том), имеющий определенный ADDRESS (NY), может добавить СТАТЬИ (Bike, Car). Наконец, BILL печатается со всей информацией.
Моя проблема: как справиться с собиранием необходимой информации (здесь: владелец, город, количество предметов) из нескольких объектов? Потому что я думаю, что глупо делать это вручную, как показано ниже (см. 4.), не так ли? (тем более, что в действительности объем информации увеличивается)
Итак, что такое «чистый способ» для создания счета / сбора информации, необходимой в этом примере?
<?php $a = new basket('Tom','NY'); $a->add_item("Bike",1.99); $a->add_item("Car",2.99); $b = new bill( $a ); $b->do_print();
1.
class basket { private $owner = ""; private $addr = ""; private $articles = array(); function basket( $name, $city ) { // Constructor $this->owner = $name; $this->addr = new addresse( $city ); } function add_item( $name, $price ) { $this->articles[] = new article( $name, $price ); } function item_count() { return count($this->articles); } function get_owner() { return $this->owner; } function get_addr() { return $this->addr; } }
2.
class addresse { private $city; function addresse( $city ) { // Constructor $this->city = $city; } function get_city() { return $this->city; } }
3.
class article { private $name = ""; private $price = ""; function article( $n, $p ) { // Constructor $this->name = $n; $this->price = $p; } }
4.
class bill { private $recipient = ""; private $city = ""; private $amount = ""; function bill( $basket_object ) { $this->recipient = $basket_object->get_owner(); $this->city = $basket_object->get_addr()->get_city(); $this->amount = $basket_object->item_count(); } function do_print () { echo "Bill for " . $this->recipient . " living in " . $this->city . " for a total of " . $this->amount . " Items."; } }
Если вы скажете «Не задавать вопрос» , вы действительно добавите метод рендеринга в счет, которому вы передадите экземпляр BillRenderer. Затем Билл расскажет БиллРендеруру, как передать законопроект. Это соответствует принципам InformationExpert и High Cohesion, которые предлагают методы быть на объектах с наибольшей информацией для выполнения задачи.
class Bill { … public function renderAs(BillRenderer $billRenderer) { $billRenderer->setRecipient($this->owner); $billRenderer->setAddress($this->address); … return $billRenderer->render(); } }
Тогда BillRenderer (интерфейс) знает формат вывода, например, вы должны писать конкретные рендереры для PlainText или HTML или PDF:
class TxtBillRenderer implements BillRenderer { … public function render() { return sprintf('Invoice for %s, %s', $this->name, $this->address); } } echo $bill->renderAs(new TxtBillRenderer);
Если ваш Билл содержит другие объекты, они также будут внедрять метод renderAs. Билл затем передал рендер на эти объекты.
Как корзина, так и счет могут иметь отношение к элементу позиций – объект, представляющий упорядоченный список из нуля или более пунктов со счетом и ценой.
Поскольку такой список является объектом его собственного, его легко обойти:
$bill = new Bill($buyer, $address, $basket->getPositions());
Однако печать законопроекта должна выполняться BillPrinter
, потому что печать не должна выполняться самим документом:
$billPrinter = new BillPrinter($bill, $printerDevice); $billPrinter->print();
Прежде всего, в PHP5 конструктор он public function __construct()
. То, что вы используете, есть способ PHP4. И затем другие проблемы с вашим кодом:
Basket
(вы имеете в виду « Cart
?»), вы должны создать экземпляр объекта адреса и передать его. Articles
(вы имеете в виду Items
?) должны создаваться на основе идентификатора, а не на основе имени. Причины этого те же, что и выше +, у вас будут проблемы с уникальностью. И тогда некоторые предметы могут иметь более низкую цену при покупке в комбинации. Вам нужен способ безопасно идентифицировать их. Что касается очистки кода там:
Bill
не должен нести ответственность за печать. Что-то вроде :
class Basket { // -- other code public function handleInvoice( Bill $invoice ) { $invoice->chargeFor( $this->items ); $invoice->chargeTo( $this->account ); return $invoice->process(); } }
.. затем используйте его как
$cart = new Basket(..); // some operation with it $invoice = new Bill; $cart->handleInvoice($invoice); $printer = new PDFPrinter; // OR new JpegPrinter; OR new FakePrinter OR anything else $printer->print( $invoice );
-$cart = new Basket(..); // some operation with it $invoice = new Bill; $cart->handleInvoice($invoice); $printer = new PDFPrinter; // OR new JpegPrinter; OR new FakePrinter OR anything else $printer->print( $invoice );
Это даст вам экземпляр Bill
вне класса, который затем вы можете распечатать или отправить кому-то.
Кроме того, вам может быть полезно наблюдать за ивовой лекцией: