OOP(有益用途)

时间:2012-04-30 17:27:53

标签: php oop

关于如何以有益的方式使用OOP的问题我假设一个BASKET,它的拥有者(Tom)有一个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.";
    }

}

3 个答案:

答案 0 :(得分:2)

如果您执行Tell Dont Ask,您确实会将一个呈现方法添加到您将传递BillRenderer实例的帐单中。比尔会告诉BillRenderer如何提交条例草案。这符合InformationExpert and High Cohesion principles,它建议使用最多信息来完成任务的对象。

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

如果您的Bill包含其他对象,那么它们也会实现renderAs方法。然后,条例草案会将渲染器传递给这些物体。

答案 1 :(得分:1)

篮子和账单都可以与头寸项目有关系 - 一个对象代表零个或多个具有计数和价格的项目的有序列表。

因为这样的列表是它自己的一个对象,所以很容易传递:

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

然而,帐单的打印应该由BillPrinter完成,因为打印本身不是账单的工作:

$billPrinter = new BillPrinter($bill, $printerDevice);
$billPrinter->print();

答案 2 :(得分:1)

首先,在PHP5中构造函数public function __construct()。您使用的是PHP4方式。然后再解决您的代码中的其他问题:

  • 而不是将城市的名称传递给Basket(你的意思是Cart吗?),你应该创建地址对象实例并传递它。 / LI>
  • 不要根据名称向购物篮中添加金额,而是添加整个商品实例,否则在切换网站语言或货币时会遇到很多问题。
  • Articles(您的意思是Items?)应该根据ID创建,而不是基于名称。原因与上述相同+您将遇到唯一性问题。然后,当组合购买时,一些物品可能具有较低的价格。您需要一种安全识别它们的方法。

至于清理那里的代码:

  • 您应该停止在构造函数中从给定参数创建实例。虽然它并不总是坏事,但在你的情况下,你在那里弄得一团糟。
  • 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 );

这会在课外提供Bill的实例,然后您可以打印或发送给某人。

此外,您可能会从观看柳叶讲座中受益: