Abstract Factory パターンとは
具体的なクラスを明確にすることなく、関連し合うオブジェクトの集まりを生成するパターン
オブジェクト指向プログラミングでは、具体的なクラスではなくインターフェースや抽象化されたクラスのAPIに対してプログラミングすることが重要になります
Abstract Factory パターンのメリット
- 具体的なクラスをクライアントから隠蔽する
- 利用する部品群の整合性を保つ
- 部品群の単位で切り替えができる
実装例
<?php
interface DaoFactory
{
public function createItemDao();
public function createOrderDao();
}
class DbFactory implements DaoFactory
{
public function createItemDao()
{
return new DbItemDao();
}
public function createOrderDao()
{
return new DbOrderDao($this->createItemDao());
}
}
class MockFactory implements DaoFactory
{
public function createItemDao()
{
return new MockItemDao();
}
public function createOrderDao()
{
return new MockOrderDao();
}
}
interface ItemDao
{
public function findById($item_id);
}
interface OrderDao
{
public function findById($order_id);
}
class DbItemDao implements ItemDao
{
const ITEM_DATA = [
1 => '商品1',
2 => '商品2',
3 => '商品3',
];
private $items;
public function __construct()
{
$this->items = [];
foreach (self::ITEM_DATA as $key => $val) {
$item = new Item($key, $val);
$this->items[$item->getId()] = $item;
}
}
public function findById($item_id)
{
if (array_key_exists($item_id, $this->items)) {
return $this->items[$item_id];
}
return null;
}
}
class DbOrderDao implements OrderDao
{
const ORDER_DATA = [
1 => '3',
2 => '1,3',
3 => '1,2,3',
4 => '2',
5 => '2,3',
];
private $orders;
public function __construct(ItemDao $item_dao)
{
$this->orders = [];
foreach (self::ORDER_DATA as $key => $val) {
$order = new Order($key);
foreach (explode(',', $val) as $item_id) {
$item = $item_dao->findById($item_id);
if (!is_null($item)) {
$order->addItem($item);
}
}
$this->orders[$order->getId()] = $order;
}
}
public function findById($order_id)
{
if (array_key_exists($order_id, $this->orders)) {
return $this->orders[$order_id];
}
return null;
}
}
class MockItemDao implements ItemDao
{
public function findById($item_id)
{
$item = new Item($item_id, 'dummy item');
return $item;
}
}
class MockOrderDao implements OrderDao
{
public function findById($order_id)
{
$order = new Order($order_id);
$order->addItem(new Item('99', 'dummy item 99'));
$order->addItem(new Item('99', 'dummy item 99'));
$order->addItem(new Item('98', 'dummy item 98'));
return $order;
}
}
class Item
{
private $id;
private $name;
public function __construct($id, $name)
{
$this->id = $id;
$this->name = $name;
}
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
}
class Order
{
private $id;
private $items;
public function __construct($id)
{
$this->id = $id;
$this->items = [];
}
public function addItem(Item $item)
{
$id = $item->getId();
if (!array_key_exists($id, $this->items)) {
$this->items[$id]['object'] = $item;
$this->items[$id]['amount'] = 0;
}
$this->items[$id]['amount']++;
}
public function getItems()
{
return $this->items;
}
public function getId()
{
return $this->id;
}
}
// // DbFactory
$factory = new DbFactory();
// MockFactory
// $factory = new MockFactory();
$item_id = 1;
$item_dao = $factory->createItemDao();
$item = $item_dao->findById($item_id);
//
echo sprintf("ITEM ID: %d Name: %s\n", $item_id, $item->getName());
$order_id = 3;
$order_dao = $factory->createOrderDao();
$order = $order_dao->findById($order_id);
echo sprintf("ORDER ID: %d\n", $order_id);
foreach ($order->getItems() as $item) {
echo sprintf("ITEM NAME: %s, AMOUNT: %d\n", $item['object']->getName(), $item['amount']);
}