forget for get

覚えるために忘れる

Abstract Factoryパターン

抽象的な工場では、抽象的な部品を組み合わせて抽象的な製品をつくる
具体的な実装には注目せず、インタフェースだけを使って、部品を組み立て、製品にまとめる

具体的な工場を新たに追加するのは簡単
部品を新たに追加するのは困難(すべての具体的な工場に追加する必要があるので)

 

Factory.php

abstract class Factory {
  static function getFactory($classname): Factory {
    try {
      return new $classname();
    } catch (Exception $e) {
      echo $e->getMessage() . "\n";
    }
  }
  abstract function createLink($caption, $url): Link;
  abstract function createTray($caption): Tray;
  abstract function createPage($title, $author): Page;
}

Item.php

abstract class Item {
  protected $caption;
  function __construct($caption) {
    $this->caption = $caption;
  }
  abstract function makeHTML();
}

Link.php

abstract class Link extends Item {
  protected $url;
  function __construct($caption, $url) {
    parent::__construct($caption);
    $this->url = $url;
  }
}

Tray.php

abstract class Tray extends Item {
  protected $tray = [];
  function __construct($caption) {
    parent::__construct($caption);
  }
  function add(Item $item) {
    $this->tray[] = $item;
  }
}

Page.php

abstract class Page {
  protected $title;
  protected $author;
  protected $content = [];
  function __construct($title, $author) {
    $this->title = $title;
    $this->author = $author;
  }
  function add(Item $item) {
    $this->content[] = $item;
  }
  function output() {
    try {
      $filename = $this->title . ".html";
      file_put_contents($filename, $this->makeHTML());
      echo $filename . "を作成しました。\n";
    } catch (Exception $e) {
      echo $e->getMessage() . "\n";
    }
  }
  abstract function makeHTML();
}

Main.php

require "../autoload.php";
if (!isset($argv[1])) {
  echo "引数を指定してください\nphp Main.php [ListFactory/TableFactory]\n";
  return;
}
$factory = Factory::getFactory($argv[1]);
$twitter = $factory->createLink("twitter", "https://twitter.com/lightwill0309");
$youtube = $factory->createLink("youtube", "https://www.youtube.com/@lightwill");
$guitarflix = $factory->createLink("ギターフリックス", "https://lightwill.tokyo/guitarflix/");
$dramamegra = $factory->createLink("ドラマメグラ", "https://dramamegra.com/");

$traySns = $factory->createTray("SNS");
$traySns->add($twitter);
$traySns->add($youtube);

$trayWeb = $factory->createTray("Webサービス");
$trayWeb->add($guitarflix);
$trayWeb->add($dramamegra);

$page = $factory->createPage("LinkPage", "lightwill");
$page->add($traySns);
$page->add($trayWeb);
$page->output();

ListFactory.php

class ListFactory extends Factory {
  function createLink($caption, $url): Link {
    return new ListLink($caption, $url);
  }
  function createTray($caption): Tray {
    return new ListTray($caption);
  }
  function createPage($title, $author): Page {
    return new ListPage($title, $author);
  }
}

ListLink.php

class ListLink extends Link {
  function __construct($caption, $url) {
    parent::__construct($caption, $url);
  }
  function makeHTML() {
    return '  <li><a href="' . $this->url . '">' . $this->caption . "</a></li>\n";
  }
}

ListTray.php

class ListTray extends Tray {
  function __construct($caption) {
    parent::__construct($caption);
  }
  function makeHTML() {
    $html = "<li>\n" . $this->caption . "\n<ul>\n";
    foreach ($this->tray as $item) {
      $html .= $item->makeHTML();
    }
    $html .= "</ul>\n</li>\n";
    return $html;
  }
}

ListPage.php

class ListPage extends Page {
  function __construct($title, $author) {
    parent::__construct($title, $author);
  }
  function makeHTML() {
    $html = "<html><head><title>" . $this->title . "</title></head>\n"
      . "<body>\n<h1>" . $this->title . "</h1>\n<ul>\n";
    foreach ($this->content as $item) {
      $html .= $item->makeHTML();
    }
    $html .= "</ul>\n<hr><address>" . $this->author . "</address></body></html>\n";
    return $html;
  }
}

TableFactory.php

class TableFactory extends Factory {
  function createLink($caption, $url): Link {
    return new TableLink($caption, $url);
  }
  function createTray($caption): Tray {
    return new TableTray($caption);
  }
  function createPage($title, $author): Page {
    return new TablePage($title, $author);
  }
}

TableLink.php

class TableLink extends Link {
  function __construct($caption, $url) {
    parent::__construct($caption, $url);
  }
  function makeHTML() {
    return '  <td><a href="' . $this->url . '">' . $this->caption . "</a></td>\n";
  }
}

TableTray.php

class TableTray extends Tray {
  function __construct($caption) {
    parent::__construct($caption);
  }
  function makeHTML() {
    $html = "<td><table><tr><td>" . $this->caption . "</td></tr>\n<tr>\n";
    foreach ($this->tray as $item) {
      $html .= $item->makeHTML();
    }
    $html .= "</tr></table></td>";
    return $html;
  }
}

TablePage.php

class TablePage extends Page {
  function __construct($title, $author) {
    parent::__construct($title, $author);
  }
  function makeHTML() {
    $html = "<html><head><title>" . $this->title . "</title></head>\n"
      . "<body>\n<h1>" . $this->title . "</h1>\n<table>\n";
    foreach ($this->content as $item) {
      $html .= "<tr>" . $item->makeHTML() . "</tr>";
    }
    $html .= "</table>\n<hr><address>" . $this->author . "</address></body></html>\n";
    return $html;
  }
}