Design Patterns PHP - Composite Java

1) At the beginning.

Let's imagine situation that we have some set of products for example in the shop. In our example we have class "Product" as representat of shop's product

Sometimes we would like to sell many products at once. This is representing by class "Pack" which contains array of "Product"


class Product
{
    /**
     * @var double
     */
    protected $cost;

    function __construct($cost)
    {
        $this->cost = $cost;
    }

    /**
     * @return double
     */
    public function getCost()
    {
        return $this->cost;
    }
}

class Pack
{
    /**
     * @var Product []
     */
    private $products = [];

    /**
     * @param Product []
     */
    function __construct($products)
    {
        $this->products = $products;
    }

    /**
     * @return double
     */
    public function getValue()
    {
        $totalValue = 0;
        foreach ($this->products as $product) {
            $totalValue += $product->getCost();
        }

        return $totalValue;
    }
}





2) What want we to compute in application?

We want to compute cost of production both class "Product" alike class "Pack"

3) How can we compute cost of products in application ?

Let's look for the following code:

chcemy obliczać wartość(koszt) tych obiektów - otrzymujemy dla przykładu jeden z tych obiektów
ale nie wiemy jakiego jest typu musimy sprawdzać typ i wyliczać koszt danego obiektu


$product = new Product(13.02);
$pack = new Pack([new Product(13.02), new Product(5.67), new Product(5.67), new Product(5.67), new Product(2.12)]);

$products = [$product, $pack];

$randomProduct = $products[rand(0, 1)];

$value = 0;

if ($randomProduct instanceof Product) {
    $value = $randomProduct->getCost();
} elseif ($randomProduct instanceof Pack) {
    $value = $randomProduct->getValue();
}




We want to compute of cost of these objects. We want to receive some object we don't know what is the type so we check this and invoke proper method.

It's not the best solution.

4) How we can improve this?

Let's notice that "Pack" we can treat as "Product". In fact it is a product - strictly speaking a compound product contains with many other products.

We should create a common interface which will implement both this classes. Let's call it "getCost".

Let's see the code in step2.