Abstract Factory

7/8/2021 OOPPattern

# Description

  • Create các object mà không cần chỉ định class cấu trúc.

# Example:

Create view template for the page

interface ViewFactory
{
    public function getPageTemplate(): PageTemplate;

    public function getRenderer(): Renderer;
}
1
2
3
4
5
6
interface PageTemplate
{
    public function getStringTemplate(): string;
}
1
2
3
4
interface Renderer
{
    public function render(string $templateString, array $arguments = []): string;
}
1
2
3
4
class Page
{
    public function render(ViewFactory $factory, $arguments): string
    {
        $renderer = $factory->getRenderer();
        $pageTemplate = $factory->getPageTemplate();
        $viewPath = $pageTemplate->getStringTemplate();
        return $renderer->render($viewPath, $arguments);
    }
}
1
2
3
4
5
6
7
8
9
10

Use PHP để render view:

class PHPTemplateFactory implements ViewFactory
{
    public function getRenderer(): Renderer
    {
        return new PHPTemplateRenderer();
    }

    public function getPageTemplate(): PageTemplate
    {
        return new PHPPageTemplate();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
class PHPPageTemplate implements PageTemplate
{
    public function getStringTemplate(): string
    {
        return <<<HTML
        <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title><?= \$title; ?></title> </head> <body> <?= \$content; ?> </body> </html>
        HTML;
    }
}
1
2
3
4
5
6
7
8
9
class PHPTemplateRenderer implements Renderer
{
    public function render(string $templateString, array $arguments = []): string
    {
        extract($arguments);

        ob_start();
        eval(' ?>' . $templateString . '<?php ');
        $result = ob_get_contents();
        ob_end_clean();

        return $result;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Use twig engine:

class TwigFactory implements ViewFactory
{
    public function getRenderer(): Renderer
    {
        return new TwigRenderer();
    }

    public function getPageTemplate(): PageTemplate
    {
        return new TwigPageTemplate();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
class TwigPageTemplate implements PageTemplate
{
    public function getStringTemplate(): string
    {
        return "index.html";
    }
}
1
2
3
4
5
6
7
class TwigRenderer implements Renderer
{
    public function render(string $templatePath, array $arguments = []): string
    {
        $loader = new \Twig\Loader\FilesystemLoader('/../src/Libs/Views');
        $twig = new \Twig\Environment($loader, [
            'cache' => '/../cache',
        ]);

        return $twig->render($templatePath, $arguments);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

Usage:

$page = new Page();
$viewFactory = new PHPTemplateFactory();
echo $page->render($viewFactory, ["title" => "Page title", "content" => "Page content"]);
1
2
3

Renderer, PageTemplate được create bằng Factory Method

  • User không cần biết logic xử lí, chỉ cần quan tâm các method của nó thông qua interface.
  • Muốn thay đổi template engine chỉ cần tạo Renderer, PageTemplate độc lập mà không cần update lại code xử lí ở Page.

Refer: https://refactoring.guru/design-patterns/abstract-factory/php/example