抽象工厂模式(Abstract Factory)

目的

在不指定具体类的情况下创建一系列相关或依赖对象。 通常创建的类都实现相同的接口。 抽象工厂的客户并不关心这些对象是如何创建的,它只是知道它们是如何一起运行的。

UML 图

抽象工厂模式(Abstract Factory)

代码

你可以在 GitHub 上找到这个代码。

Product.php

  1. <?php
  2. namespace DesignPatterns\Creational\AbstractFactory;
  3. interface Product
  4. {
  5. public function calculatePrice(): int;
  6. }

ShippableProduct.php

  1. <?php
  2. namespace DesignPatterns\Creational\AbstractFactory;
  3. class ShippableProduct implements Product
  4. {
  5. /**
  6. * @var float
  7. */
  8. private $productPrice;
  9. /**
  10. * @var float
  11. */
  12. private $shippingCosts;
  13. public function __construct(int $productPrice, int $shippingCosts)
  14. {
  15. $this->productPrice = $productPrice;
  16. $this->shippingCosts = $shippingCosts;
  17. }
  18. public function calculatePrice(): int
  19. {
  20. return $this->productPrice + $this->shippingCosts;
  21. }
  22. }

DigitalProduct.php

  1. <?php
  2. namespace DesignPatterns\Creational\AbstractFactory;
  3. class DigitalProduct implements Product
  4. {
  5. /**
  6. * @var int
  7. */
  8. private $price;
  9. public function __construct(int $price)
  10. {
  11. $this->price = $price;
  12. }
  13. public function calculatePrice(): int
  14. {
  15. return $this->price;
  16. }
  17. }

ProductFactory.php

  1. <?php
  2. namespace DesignPatterns\Creational\AbstractFactory;
  3. class ProductFactory
  4. {
  5. const SHIPPING_COSTS = 50;
  6. public function createShippableProduct(int $price): Product
  7. {
  8. return new ShippableProduct($price, self::SHIPPING_COSTS);
  9. }
  10. public function createDigitalProduct(int $price): Product
  11. {
  12. return new DigitalProduct($price);
  13. }
  14. }

测试

Tests/AbstractFactoryTest.php

  1. <?php
  2. namespace DesignPatterns\Creational\AbstractFactory\Tests;
  3. use DesignPatterns\Creational\AbstractFactory\DigitalProduct;
  4. use DesignPatterns\Creational\AbstractFactory\ProductFactory;
  5. use DesignPatterns\Creational\AbstractFactory\ShippableProduct;
  6. use PHPUnit\Framework\TestCase;
  7. class AbstractFactoryTest extends TestCase
  8. {
  9. public function testCanCreateDigitalProduct()
  10. {
  11. $factory = new ProductFactory();
  12. $product = $factory->createDigitalProduct(150);
  13. $this->assertInstanceOf(DigitalProduct::class, $product);
  14. }
  15. public function testCanCreateShippableProduct()
  16. {
  17. $factory = new ProductFactory();
  18. $product = $factory->createShippableProduct(150);
  19. $this->assertInstanceOf(ShippableProduct::class, $product);
  20. }
  21. public function testCanCalculatePriceForDigitalProduct()
  22. {
  23. $factory = new ProductFactory();
  24. $product = $factory->createDigitalProduct(150);
  25. $this->assertEquals(150, $product->calculatePrice());
  26. }
  27. public function testCanCalculatePriceForShippableProduct()
  28. {
  29. $factory = new ProductFactory();
  30. $product = $factory->createShippableProduct(150);
  31. $this->assertEquals(200, $product->calculatePrice());
  32. }
  33. }