ООП (выгодное использование)

на мой вопрос оhow to use OOP in a beneficial way В качестве примера я предполагаю КОРЗИНУ, к которой ее владелец (Том), имеющий определенный АДРЕС (Нью-Йорк), может добавить СТАТЬИ (Велосипед, Автомобиль). Наконец, БИЛЛ напечатан со всей этой информацией.

Моя проблема: Как справиться со сбором нужной информации (здесь: владелец, город, количество предметов) из нескольких объектов? Потому что я думаю, что глупо делать это вручную, как это сделано ниже (см. 4.), не так ли? (даже больше, поскольку объем информации в реальности увеличивается)

Так что же такое «чистый путь»? для создания счета / сбора информации, необходимой в этом примере?

<code><?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();
</code>

1.

<code>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;
    }

}
</code>

2.

<code>class addresse {

    private $city;

    function addresse( $city ) {
        // Constructor
        $this->city = $city;
    }

    function get_city() {
        return $this->city;
    }

}
</code>

3.

<code>class article {

    private $name = "";
    private $price = "";

    function article( $n, $p ) {
        // Constructor
        $this->name = $n;
        $this->price = $p;
    }   

}
</code>

4.

<code>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.";
    }

}
</code>
 halfer30 апр. 2012 г., 19:38
@Lion - не могли бы вы изложить свои возражения против корзины? Кто-то думает так же, как и вы (у вас есть флажок + ve рядом с вашим комментарием), но мне неясно, почему это не может быть объектом.
 Tom30 апр. 2012 г., 19:41
@Justin: Хорошо, но, тем не менее, в этом примере я должен получить значение города из объекта ADDRESS & quot; вручную & quot ;? И в «реальном сценарии приложения» было бы еще больше информации. Так действительно ли это чистый способ сбора всей этой информации вручную?
 halfer30 апр. 2012 г., 19:42
(Мои комментарии в стороне, а не ответ на вопрос. Надеюсь, полезно!).
 halfer30 апр. 2012 г., 19:40
@Tom - быстрый совет. Поскольку вы работаете с объектами, PHP позволяет вам строго набирать параметры вашего функционального объекта, что, в свою очередь, помогает уменьшить количество ошибок. Вместоfunction bill( $basket_object ) делатьfunction __construct( Basket $basket_object ), Вы можете видеть, что я изменил имя вашего конструктора (ваш подход устарел), и я думаю, что camel-case обычно рекомендуется также для имен классов.
 Justin ᚅᚔᚈᚄᚒᚔ30 апр. 2012 г., 19:35
Счет действительно не должен быть отдельным классом, поскольку вся информация, которую вы собираете, уже находится в объекте корзины. Вы можете просто добавитьprint_bill() функция в корзину.

Ответы на вопрос(3)

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

Поскольку такой список является его собственным объектом, его легко обойти:

$bill = new Bill($buyer, $address, $basket->getPositions());

Однако печать счета должна быть сделанаBillPrinterпотому что это не работа счета, чтобы напечатать себя:

$billPrinter = new BillPrinter($bill, $printerDevice);
$billPrinter->print();
 30 апр. 2012 г., 19:41
@Malovich: часто рядом с покупателем счет может иметь дополнительный адрес (адрес, на который отправляется счет, но это не адрес покупателя, а физическое / юридическое лицо, для которого предназначен счет).
 Tom30 апр. 2012 г., 19:52
Итак, здесь Bill-Constructor будет собирать всю необходимую информацию из $ customer-, $ address- и каждого предмета-объекта? Там нет пути обойти это?
 30 апр. 2012 г., 19:40
Кроме того, адрес не должен быть собственностью $ покупателя? Или есть функциональная причина, по которой адрес требует свой собственный объект?
 30 апр. 2012 г., 20:15
@hakre: Это имело бы смысл, если доступны сторонние покупки, при этом отслеживание адресов выставления счетов и доставки по-прежнему будет относиться к отдельной учетной записи, не так ли? Ммм. Это не простая вещь, не так ли?

public function __construct(), То, что вы используете, это путь PHP4. И затем есть другие проблемы с вашим кодом:

instead of passing the name of the city to the Basket ( do you mean Cart ?), you should be creating the address object instance and passing it. do not add items based on name an amount of money to the basket, instead add the whole instance of item, otherwise you will have a lot of problems when switching site language or currency. the Articles (do you mean Items ?) should be created based on ID, not based on name. The reasons for that are the same as above + you will have issues with uniqueness. And then some of items might have lower price, when bought in combination. You need a way to safely identify them.

Что касается очистки кода там:

you should stop creating instance from given parameters in the constructor. While it is not always a bad thing, in your case you are making a mess there. Bill should not be responsible for printing itself.

Что-то вроде :

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 );

Это даст вам экземплярBill вне класса, который затем вы можете распечатать или отправить кому-то.

Кроме того, вы могли бы извлечь выгоду от просмотра лекции ивы:

Inheritance, Polymorphism, & Testing Don't Look For Things! Clean Code I: Arguments

Скажи не спрашивайВы действительно добавили бы метод рендеринга в счет, к которому вы бы передали экземпляр BillRenderer. Затем Билл скажет БиллРендереру, как сделать Билл. Это в соответствии сInformationExpert и принципы высокой сплоченности которые предлагают методы на объектах с наибольшим количеством информации для выполнения задачи.

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. Затем Билл передаст визуализатор этим объектам.

Ваш ответ на вопрос