初识设计模式——简单工厂模式、策略模式及两者的结合使用

简单工厂模式

简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

简单工厂模式中工厂对象的主要功能为决定创建出哪一种产品类,所以,工厂类中是存在判断的。以实现一个简单的计算器为例,代码如下:

客户端代码:

<?php

$numberA = isset($_GET['a'])?$_GET['a']:0;
$numberB = isset($_GET['b'])?$_GET['b']:0;
$type = isset($_GET['type'])?$_GET['type']:'+';

include './Factory.php';

$server = Factory::getClaculator($type);
if (empty($server))
    $result = 0;
else
    $result = $server->evaluate($numberA, $numberB);

var_dump($result);

工厂类代码:

<?php

include './Claculator.php';
include './claculator/Add.php';
include './claculator/Divide.php';
include './claculator/Tract.php';
include './claculator/Ride.php';

class Factory
{
    public static function getClaculator($type)
    {
        switch ($type)
        {
            case '+' :
                $server = new Add();
                break;
            case '-' :
                $server = new Tract();
                break;
            case '*' :
                $server = new Ride();
                break;
            case '/' :
                $server = new Divide();
                break;
            default :
                $server = null;
                break;
        }
        return $server;
    }
}

计算类统一接口:

<?php

Interface Claculator
{
    function evaluate($numberA, $numberB);
}

加法类:

<?php

class Add implements Claculator
{
    public function evaluate($numberA, $numberB)
    {
        return $numberA+$numberB;
    }
}

减法类:

<?php

class Tract implements Claculator
{
    public function evaluate($numberA, $numberB)
    {
        return $numberA-$numberB;
    }
}

乘法类:

<?php

class Ride implements Claculator
{
    public function evaluate($numberA, $numberB)
    {
        return $numberA*$numberB;
    }
}

除法类:

<?php

class Divide implements Claculator
{
    public function evaluate($numberA, $numberB)
    {
        if ($numberB==0)
            return null;
        return $numberA/$numberB;
    }
}

UML图:

简单工厂模式主要减少了客户端代码的修改,降低了耦合性。举个例子,假如我们现在需要扩展这个计算器,为这个计算器加一个平方根的计算功能,我们只需要增加一个SquareRoot类继承Claculator接口,在简单工厂中增加一条分支即可,无需改变客户端的代码。但是设计模式的六大原则中存在一个开闭原则(Open-Closed Principle, OCP),其中的Factory显然违背了这一原则,所以简单工厂模式并不属于23种GOF设计模式之一,而工厂模式与简单工厂模式的区别主要也在这里。工厂模式下一篇整理。

策略模式

策略模式定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户

示例:在实际项目中,我们经常使用接口用来做数据对接,而JSON格式和XML格式常作为对接数据的格式,我们可以使用策略模式进行封装。

客户端:

<?php

include './Strategy.php';
include './strategy/JsonData.php';
include './strategy/XmlData.php';

Class Client
{
    public static function index($type)
    {
        $data = [
            ['name' => 'renling', 'age' => '18', 'sex' => '1'],
            ['name' => 'renling', 'age' => '18', 'sex' => '1'],
            ['name' => 'renling', 'age' => '18', 'sex' => '1'],
            ['name' => 'renling', 'age' => '18', 'sex' => '1']
        ];
        switch ($type) {
            case 'json':
                $server = new JsonData();
                break;
            case 'xml':
                $server = new XmlData();
                break;
            default :
                $server = null;
                break;
        }
        if (empty($server)) {
            return '';
        } else {
            $server->getData($data);
        }
    }
}
$type = isset($_GET['type'])?$_GET['type']:'json';
Client::index($type);

策略抽象类:

<?php

interface ResponseStrategy
{
    function getData($data);
}

JSON格式对象:

<?php

class JsonData implements ResponseStrategy
{
    public function getData($data)
    {
        ob_end_clean();
        header('Content-Type:application/json');
        echo json_encode($data, JSON_UNESCAPED_UNICODE);
        die;
    }
}

XML格式对象(封装XML的方法是仿照thinkphp5写的):

<?php

class XmlData implements ResponseStrategy
{
    public function getData($data)
    {
        $options = [
            // 根节点名
            'root_node' => 'strategy',
            // 根节点属性
            'root_attr' => '',
            //数字索引的子节点名
            'item_node' => 'item',
            // 数字索引子节点key转换的属性名
            'item_key'  => 'id',
            // 数据编码
            'encoding'  => 'utf-8',
        ];
        $data = $this->xmlEncode($data, $options['root_node'], $options['item_node'], $options['root_attr'], $options['item_key'], $options['encoding']);
        ob_end_clean();
        header('Content-Type:text/xml');
        echo $data;die;
    }
    protected function xmlEncode($data, $root, $item, $attr, $id, $encoding)
    {
        if (is_array($attr)) {
            $array = [];
            foreach ($attr as $key => $value) {
                $array[] = "{$key}=\"{$value}\"";
            }
            $attr = implode(' ', $array);
        }
        $attr = trim($attr);
        $attr = empty($attr) ? '' : " {$attr}";
        $xml  = "<?xml version=\"1.0\" encoding=\"{$encoding}\"?>";
        $xml .= "<{$root}{$attr}>";
        $xml .= $this->dataToXml($data, $item, $id);
        $xml .= "</{$root}>";
        return $xml;
    }
    protected function dataToXml($data, $item, $id)
    {
        $xml = $attr = '';
        if ($data instanceof Collection || $data instanceof Model) {
            $data = $data->toArray();
        }

        foreach ($data as $key => $val) {
            if (is_numeric($key)) {
                $id && $attr = " {$id}=\"{$key}\"";
                $key         = $item;
            }
            $xml .= "<{$key}{$attr}>";
            $xml .= (is_array($val) || is_object($val)) ? $this->dataToXml($val, $item, $id) : $val;
            $xml .= "</{$key}>";
        }
        return $xml;
    }
}

我们可以通过访问Client.php?type=xml或者Client.php?type=json来获取不同格式的数据。

UML图:

策略模式与简单工厂模式的区别

  1. 所属类别不同。总体来说设计模式分为五大类,分别为创建型模式、结构型模式、行为型模式、并发型模式和线程池模式,而策略模式属于行为型模式、简单工厂模式则属于创建型模式(PS:由于简单工厂不属于不属于23种GOF设计模式之一,所以我是根据工厂模式划分的)。
  2. 简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,而策略模式是由客户端的代码自行判断创建哪一种产品的实例。
  3. 作用不一样。简单工厂模式只负责创建出产品类,而策略模式定义一系列的算法,并把它们一个个封装起来,并且使它们可相互替换(JsonData和XmlData可以相互替换)。
  4. 需要注意的一点是,策略模式定义的不同算法是可以相互替换并能完成相同的功能的。

两者的结合使用

两者结合使用时,将客户端的判断使用哪一种对象的代码放到简单工厂类中就好了,只需要修改Client类和增加Factory类即可,其余的与策略模式代码一致。

客户端:

<?php

include './Factory.php';

Class Client
{
    public static function index($type)
    {
        $data = [
            ['name' => 'renling', 'age' => '18', 'sex' => '1'],
            ['name' => 'renling', 'age' => '18', 'sex' => '1'],
            ['name' => 'renling', 'age' => '18', 'sex' => '1'],
            ['name' => 'renling', 'age' => '18', 'sex' => '1']
        ];
        Factory::getData($data, $type);
    }
}
$type = isset($_GET['type'])?$_GET['type']:'json';
Client::index($type);

简单工厂类:

<?php

include './Strategy.php';
include './strategy/JsonData.php';
include './strategy/XmlData.php';

class Factory
{
    public static function getData($data, $type = 'json')
    {
        switch ($type) {
            case 'json':
                $server = new JsonData();
                break;
            case 'xml':
                $server = new XmlData();
                break;
            default :
                $server = null;
                break;
        }
        if (empty($server)) {
            return '';
        } else {
            $server->getData($data);
        }
    }
}

UML图:

下一篇

初识设计模式——工厂模式

猜你喜欢

转载自blog.csdn.net/cuixiaogang110/article/details/82620008