02 02 2020

抽象工厂模式

模式定义

抽象工厂模式为一组相关或相互依赖的对象创建提供接口,而无需指定其具体实现类。抽象工厂的客户端不关心如何创建这些对象,只关心如何将它们组合到一起。该设计模式实现了设计模式的依赖倒置原则,因为最终由具体子类创建具体组件。


抽象工厂模式的优势

提供一个间接的层(即“抽象工厂”)抽象一组相关或依赖对象的创建而不是直接指定具体实现类。该“工厂”对象的职责是为不同平台提供创建服务。客户端不需要直接创建平台对象,而是让工厂去做这件事。 这种机制让替换平台变得简单,因为抽象工厂的具体实现类只有在实例化的时候才出现,如果要替换的话只需要在实例化的时候指定具体实现类即可。


代码实现

AbstractFactory\AbstractFactory.class.php
<?php
namespace AbstractFactory;

/*
 * 抽象工厂类
 *
 */
abstract class AbstractFactory
{
    abstract public function createText($content);

    abstract public function createPicture($path, $name);
}



JsonFactory和HtmlFactory是具体工厂,它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。

AbstractFactory\JsonFactory.class.php
<?php
namespace AbstractFactory;

use AbstractFactory\Json\Picture;
use AbstractFactory\Json\Text;

/*
 * 创建json组件的具体工厂类
 */
class JsonFactory extends AbstractFactory
{
    public function createPicture($path, $name)
    {
        return new Picture($path, $name);
    }

    public function createText($content)
    {
        return new Text($content);
    }
}


AbstractFactory\HtmlFactory.class.php
<?php
namespace AbstractFactory;
use AbstractFactory\Html\Picture;
use AbstractFactory\Html\Text;

/*
 * 创建html组件的具体工厂类
 */
class HtmlFactory extends AbstractFactory
{
    public function createPicture($path, $name)
    {
        return new Picture($path, $name);
    }

    public function createText($content)
    {
        return new Text($content);
    }
}


该接口不是抽象工厂设计模式的一部分

AbstractFactory\MediaInterface.class.php
<?php
namespace AbstractFactory;

interface MediaInterface
{
    public function render();
}


Picture、Text 是抽象产品,它是具体产品继承的父类或者是实现的接口。一般有抽象类或者接口来实现。

AbstractFactory\Picture.class.php
<?php
namespace AbstractFactory;

/*
 * 创建图片产品的抽象类
 */
abstract class Picture implements MediaInterface
{
    protected $path;
    protected $name;

    public function __construct($path, $name = '')
    {
        $this->name = (string) $name;
        $this->path = (string) $path;
    }
}


AbstractFactory\Text.class.php
<?php
namespace AbstractFactory;

/*
 * 创建文本产品的抽象类
 */
abstract class Text implements MediaInterface
{
    protected $text;

    public function __construct($text)
    {
        $this->text = (string) $text;
    }
}


Html\Picture、Html\Text、Json\Picture和Json\Text都是具体产品,具体工厂角色所创建的对象就是此角色的实例。由具体的类来实现。

AbstractFactory\Html\Picture.class.php
<?php

namespace AbstractFactory\Html;

use AbstractFactory\Picture as BasePicture;

/*
 * html组件创建图片的具体类
 */
class Picture extends BasePicture
{
    public function render()
    {
        return sprintf('<img src="%s" title="%s">', $this->path, $this->name);
    }
}


AbstractFactory\Html\Text.class.php
<?php
namespace AbstractFactory\Html;

use AbstractFactory\Text as BaseText;

/*
 * html组件创建文本的具体类
 */
class Text extends BaseText
{
    public function render()
    {
        return '<div>' . htmlspecialchars($this->text) . '</div>';
    }
}


AbstractFactory\Json\Picture.class.php
<?php
namespace AbstractFactory\Json;

use AbstractFactory\Picture as BasePicture;

/*
 * json组件创建图片的具体类
 */
class Picture extends BasePicture
{
    public function render()
    {
        return json_encode(array('title' => $this->name, 'path' => $this->path));
    }
}


AbstractFactory\Json\Text.class.php
<?php
namespace AbstractFactory\Json;

use AbstractFactory\Text as BaseText;

/*
 * json组件创建文本的具体类
 */
class Text extends BaseText
{
    public function render()
    {
        return json_encode(array('content' => $this->text));
    }
}


测试方法

AbstractFactory\AbstractFactoryTest.php
<?php

spl_autoload_register(function ($className){
    $className = str_replace('\\','/',$className);
    include $className.".class.php";
});

use AbstractFactory\HtmlFactory;
use AbstractFactory\JsonFactory;

$htmlFactory = new HtmlFactory();
$htmlTextResult = $htmlFactory->createText('抽象工厂')->render();
$htmlPictureResult = $htmlFactory->createPicture('test.png', '抽象工厂')->render();

$jsonFactory = new JsonFactory();
$jsonTextResult = $jsonFactory->createText("抽象工厂")->render();
$jsonPictureResult = $jsonFactory->createPicture('test.png', '抽象工厂')->render();

echo $htmlTextResult . "\n";
echo $htmlPictureResult . "\n";
echo $jsonTextResult . "\n";
echo $jsonPictureResult . "\n";


测试示例

php AbstractFactory/AbstractFactoryTest.php 

输出:
<div>抽象工厂</div>
<img src="test.png" title="抽象工厂">
{"content":"\u62bd\u8c61\u5de5\u5382"}
{"title":"\u62bd\u8c61\u5de5\u5382","path":"test.png"}


总结

我们以工厂生产产品为例,所谓抽象工厂模式就是我们的抽象工厂约定了可以生产的产品,这些产品都包含多种规格,然后我们可以从抽象工厂为每一种规格派生出具体工厂类,然后让这些具体工厂类生产具体的产品。

以上示例中

AbstractFactory是抽象工厂,这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。它由抽象类或者接口来实现。

JsonFactory和HtmlFactory是具体工厂,它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。

Picture、Text 是抽象产品,它是具体产品继承的父类或者是实现的接口。一般有抽象类或者接口来实现。

Html\Picture、Html\Text、Json\Picture和Json\Text都是具体产品,具体工厂角色所创建的对象就是此角色的实例。由具体的类来实现。

客户端需要HTML格式的Text,调用HtmlFactory的createText方法即可,而不必关心其实现逻辑。




代码地址:https://github.com/798256478/design-patterns/tree/master/AbstractFactory