栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > PHP

PHP设计模式-几种工厂模式的对比

PHP 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

PHP设计模式-几种工厂模式的对比

工厂模式

在讲解工厂模式之前,我们先来探讨一些问题,研究是为什么会出现工厂模式的,工厂模式有什么优缺点。

以超人为例子:有一个超人,超人一定有对种超能力;
于是我们建立一个超人类

namespace Factory;class Superman{
    
}

同时创建超能力类并给超人添加超能力;

namespace Factory;class Flight{    
    protected $name;    
    protected $ability;    public function __construct($name, $ability)
    {        $this->name    = $name;        $this->ability = $ability;
    }
}class Force {    //该类的属性和方法}class Jog{    //该类的属性和方法}

给超人添加超能力

namespace Factory;class Superman{    public function __construct()
    {
        $power_class = new Power('超能力', 1000);
        $force_class = new Force();
        $jog_class   = new Jog();
        
    }
   
}

通过上面的代码可以得到:

  • 超人要添加一个超能力就必须new个能力类

  • 如果能力类的参数需要修改,那么实例化的参数要需要修改

  • 能力类的名称觉得不合理,那么调用的代码也要修改


如果上面的修改出现在多个不同的地方,那么我们就会花费很多时间或精力去修改这个东西。所以我们可以引出工厂模式,去解决这些问题。

简单工厂模式问题1:
  • 前提: 在超人的超能力不多的情况下(只有一两个已知的)

  • 懒: 不想在每次添加添加超能力的时候,写new

  • 超能力(服务端)不想让超人(client)知道有哪些超能力类--面向接口

解决方案:简单工厂模式
  • 首先创建工厂

namespace Factory;class SimpleFactory{    protected $power_type = [        'force' => __NAMESPACE__ . 'Force',
    ];    
    public function addPower($type)
    {        if (!array_key_exists($type, $this->power_type)) {            throw new Exception("超能力不存在");
        }

        $class_name = $this->power_type[$type];        return new $class_name;
    }
}
  • 超能力

namespace Factory;class Force extends SimpleFactory{    public function setPower()
    {        echo "超能力:力量" . PHP_EOL;
    }
}
  • 用法

addPower('force')->setPower();
} catch (Exception $e) {    echo $e->getMessage();
}
总结
  • 使用前提:当工厂知道所有要生产的类型(子类比较少),可以使用简单工厂模式。

  • 优点:可以使用户根据获得对应类类型,避免了直接实例化类,降低耦合度(面向接口开发:客户端不用知道服务的有哪些类,只要知道类型就可以了);

  • 缺点:可实例化的类型在编辑期间已经被确定,如果增加新类型,则需要修改工厂,不符合开闭原则。


静态工厂模式问题2: 如果不想在调用的时候new容器解决:使用静态工厂模式
  • 使用该模式现在我们只要对工厂类的代码修改一下

namespace Factory;class SimpleFactory{    protected $power_type = [        'force' => __NAMESPACE__ . 'Force',
    ];    
    public static function addPower($type)
    {        if (!array_key_exists($type, self::power_type)) {            throw new Exception("超能力不存在");
        }

        $class_name = self::power_type[$type];        return new $class_name;
    }
}
总结

与简单工厂类似,该模式用于创建一组相关或依赖的对象,不同之处在于静态工厂模式使用一个静态方法来创建所有类型的对象,该静态方法通常是 factory 或  build。


因为上面的超能力只有一个,所以不会出现调用超能力方法不一样的情况;如果现在超能力有多个的化,我们最后规范一下超能力调用方法接口。因此引入超能力的接口类。(也可以理解成面向接口开发,这样别人就能够更加方便调用)

  • 增加能力接口类

namespace Factory;interface PowerInterface{    public function setPower();
}
  • 对超能力类改造并增加一个超能力类

namespace Factory;class Force implements PowerInterface{    public function setPower()
    {        echo "超能力:力量" . PHP_EOL;
    }
}
namespace Factory;class Jog implements PowerInterface{    public function setPower()
    {       echo "超能力:跑步";
    }
}
  • 对简单工厂类优化一下

namespace Factory;class SimpleFactory{    protected $module; //超能力类对象

    
    public function __construct(PowerInterface $type)
    {        $this->module = $type;
    }    
    public function addPower()
    {        $this->module->setPower();
    }
}

抽象工厂模式问题3:
  • 上面超能力和工厂比较少,如果现在要一下生产大量并且具有多种超能力的超人。

  • 如果上一个方法没有对工厂代码使用依赖注入的话,添加一种超能力还得在超能力类型变量种添加一个参数;这样的违反开闭原则(可以扩张,不能修改);

解决:
  • 这里我们利用多个工厂——抽象工厂模式,定义一个抽象工厂,其他的在此上面扩展,就不用修改原来的代码。也不会违反开闭原则。

  • 生产多种超人——接口规范超人能力调用,防止不一样

首先对工厂进行操作
  • 创建一个工厂方法抽象类FactoryMethod.php,用来添加超能力

namespace Factory;abstract class FactoryMethod{    const JOG = 1;    const FORCE = 2;    
    abstract protected function activate($type);    
    public function addPower($type)
    {
        $obj = $this->activate($type);
        $obj->setPower();        return $obj;
    }
}
  • 添加工厂1(FactoryOne.php)

namespace Factory;use Exception;class FactoryOne extends FactoryMethod{    protected function activate($type)
    {        switch ($type) {            case parent::JOG :                return new Jog();                break;            case parent::FORCE :                return new Force();                break;            default :                throw new Exception("this type is not a valid power");
        }
    }
}
  • 添加工厂2(FactoryTwo.php)

namespace Factory;use Exception;class FactoryTwo extends FactoryMethod{    public function activate($type)
    {        switch ($type) {            case parent::JOG :                return new Jog();                break;            case parent::FORCE :                return new Force();                break;            default :                throw new Exception("this type is not a valid power");
        }
    }
}

工厂1和工厂2继承工厂方法抽象类,实现创建超能力(工厂里边存放实现超能力的对象),所以工厂实际上就是,把创建对象的过程封装起来,随时可以产生一个新的对象。

然后就是对超能力的操作
  • 创建一个超能力的接口类PowerInterface.php(利用接口规范超能力)

namespace Factory;interface PowerInterface{    public function setPower();
}
  • 超能力1

namespace Factory;class Force implements PowerInterface{    public function setPower()
    {        echo "超能力:力量" . PHP_EOL;
    }
}
  • 超能力2

namespace Factory;class Jog implements PowerInterface{    public function setPower()
    {       echo "超能力:跑步";
    }
}

到这里工厂方法模式已经完成了,现在我们先继续把创建超人的代码完成。

最后创建超人类Superman.php
namespace Factory;class Superman{    protected $module;    
    public function __construct(FactoryMethod $factory)
    {        $this->module = $factory;
    }    
    public function addSuperman($type)
    {        $this->module->addPower($type);
    }
}

现在我们创建超人就非常方便了

addSuperman(1);//利用工厂2 创建超人(超能力是大力)$superman_2 = new Superman(new FactoryTwo());
$superman_2->addSuperman(2);

定义多个工厂,每个工厂生产不同的超人的超能力实例,支持增加超能力类型,或工厂生产哪中超能力。

创建超人的时候,我们不用关注工厂是如何创建超人的,我们只关注工厂(工厂抽象方法类)提供的接口就可以了。这样看来工厂就是将创造超能力(多个对象)的过程封装起来



作者:PHP的艺术编程
链接:https://www.jianshu.com/p/c7d9590b91d7


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/227379.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号