@Chiang
2019-12-11T10:46:09.000000Z
字数 11897
阅读 924
设计模式 Laravel
- 工厂模式作为一种创建型设计模式,是我们最常用的实例化对象模式,是用工厂方法代替new操作的一种模式
- 工厂模式的目的是为了最大限度的减少依赖,实现解耦,把类的实例对象通过工厂去实现,实现可扩展性
IOC,DI的实现依据reflection反射, 类型约束, 服务容器(IocContainer)
写在前面我的理解:
- 简单工厂模式: 添加新产品(扩展)相当于在工厂里再添加一条生产线(属性)专门生产
- 工厂方法模式: 添加新产品(扩展)相当于再建一个子工厂(子类)专门生产
- 抽象工厂模式: 在多个产品中寻找共性,抽象出来在现有工厂中添加生产线实现
- 帮助封装
- 解耦
- 违反了开发封闭原则(开闭原则, 对修改封闭,对扩展开放,实现热插拔),有新的扩展的时候还是要到工厂类里去修改
- 被创建的实例对象,可以是接口抽象类也可以是具体的类
- 运算操作(+-*/)
- 支付操作(alipay,wechatpay,paypal)
- 缓存支持(MySQL,Redis,file)
同一种业务类型的功能,独立实现,独立调用
<?php/*** 不用设计模式时** @author Luffy (lufei@swoole.com)* @date 2019/9/19* @copyright Swoole, Inc.* @package sy-records/design-patterns*/class WeChatPay{public function pay(){}}class AliPay{public function pay(){}}$we = new WeChatPay();$we->pay();$ali = new AliPay();$ali->pay();

<?php/*** User: lufei* Date: 2019/9/15* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\SimpleFactory;/*** Interface PaySimpleFactory* @package Luffy\DesignPatterns\Factory\SimpleFactory*/interface PaySimpleFactory{public function pay();}
<?php/*** User: lufei* Date: 2019/9/15* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\SimpleFactory;/*** Class AliPay* @package Luffy\DesignPatterns\Factory\SimpleFactory*/class AliPay implements PaySimpleFactory{public function pay(){echo "我是AliPay\n";}}
<?php/*** User: lufei* Date: 2019/9/15* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\SimpleFactory;/*** Class WeChatPay* @package Luffy\DesignPatterns\Factory\SimpleFactory*/class WeChatPay implements PaySimpleFactory{public function pay(){echo "我是WeChatPay\n";}}
<?php/*** User: lufei* Date: 2019/9/15* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\SimpleFactory;/*** Class SimpleFactory* @package Luffy\DesignPatterns\Factory\SimpleFactory*/class SimpleFactory{public function pay($operate){switch ($operate) {case 'WeChatPay':$result = new WeChatPay();break;case 'AliPay':$result = new AliPay();break;default:throw new \InvalidArgumentException('暂不支持的支付方式');}return $result;}}
<?php/*** User: lufei* Date: 2019/9/15* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\SimpleFactory;/*** Class StaticFactory* @package Luffy\DesignPatterns\Factory\SimpleFactory*/class StaticFactory{public static function pay($operate){switch ($operate) {case 'WeChatPay':$result = new WeChatPay();break;case 'AliPay':$result = new AliPay();break;default:throw new \InvalidArgumentException('暂不支持的支付方式');}return $result;}}
这样客户端只需要依赖工厂类就可以调用多个支付方法
<?php/*** User: lufei* Date: 2019/9/15* Email: lufei@swoole.com*/include __DIR__ . '/../../vendor/autoload.php';// 调用use Luffy\DesignPatterns\Factory\SimpleFactory\SimpleFactory;use Luffy\DesignPatterns\Factory\SimpleFactory\StaticFactory;$pay1 = StaticFactory::pay("WeChatPay");$pay1->pay();$factory = new SimpleFactory();$pay2 = $factory->pay("AliPay");$pay2->pay();
- 抽象类要被子类继承,接口要被类实现。
- 接口只能做方法声明,抽象类中可以作方法声明,也可以做方法实现。
- 接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
- 接口是设计的结果,抽象类是重构的结果。
- 抽象类和接口都是用来抽象具体对象的,但是接口的抽象级别最高。
- 抽象类可以有具体的方法和属性,接口只能有抽象方法和不可变常量。
- 抽象类主要用来抽象类别,接口主要用来抽象功能。
- 解决了简单工厂模式中的开闭原则
- 类的实例化延迟到了子类
- 存在大量的子类工厂
要实例化的对象充满不确定,也有可能改变,不确定有多少种类进行实例化

具体的工厂类和具体的支付类实现一一对应
<?php/*** User: lufei* Date: 2019/9/19* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\FactoryMethod;interface createPay{public function pay();}
<?php/*** User: lufei* Date: 2019/9/15* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\FactoryMethod;/*** Class AliPay* @package Luffy\DesignPatterns\Factory\FactoryMethod*/class AliPay implements createPay{public function pay(){echo "我是AliPay\n";}}
<?php/*** User: lufei* Date: 2019/9/15* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\FactoryMethod;/*** Class WeChatPay* @package Luffy\DesignPatterns\Factory\FactoryMethod*/class WeChatPay implements createPay{public function pay(){echo "我是WeChatPay\n";}}
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\FactoryMethod;/*** Interface CreatePayFactoryMethod* @package Luffy\DesignPatterns\Factory\FactoryMethod*/interface CreatePayFactoryMethod{public function create();}
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\FactoryMethod;class FactoryAli implements CreatePayFactoryMethod{function create(){// TODO: Implement create() method.return new AliPay();}}
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\FactoryMethod;class FactoryWeChat implements CreatePayFactoryMethod{function create(){// TODO: Implement create() method.return new WeChatPay();}}
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/include __DIR__ . '/../../vendor/autoload.php';use Luffy\DesignPatterns\Factory\FactoryMethod\FactoryAli;use Luffy\DesignPatterns\Factory\FactoryMethod\FactoryWeChat;/*** 具体生产对象并执行对象方法测试*/class Client{public function index(){$factory = new FactoryAli();$ali = $factory->create();$ali->pay();$factory = new FactoryWeChat();$wechat = $factory->create();$wechat->pay();}}// 执行$demo = new Client;$demo->index();
- 产品客户端完全分离
- 重复工作多
- 利用简单工厂来优化抽象工厂
- 利用反射来优化抽象工厂
- 在现有产品上添加新的产品族是比较方便的(寻找产品共性抽象提取)
- 是在简单工厂模式上提取产品共性的更加抽象化而已
不确定对应的实例化对象的时候

<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\AbstractFactory;/*** 工厂接口* Interface Factory* @package Luffy\DesignPatterns\Factory\AbstractFactory*/interface Factory{/*** @return mixed*/public function createHuMan();/*** @return mixed*/public function createMonkey();}
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\AbstractFactory;/*** 具体工厂类* Class ManFactory* @package Luffy\DesignPatterns\Factory\AbstractFactory*/class ManFactory implements Factory{/*** @return Man|mixed*/public function createHuMan(){return new Man();}public function createMonkey(){return new ApeMonkey();}}
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\AbstractFactory;/*** Class WoManFactory* @package Luffy\DesignPatterns\Factory\AbstractFactory*/class WoManFactory implements Factory{public function createHuMan(){return new WoMan();}public function createMonkey(){return new FemaleMonkey();}}
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\AbstractFactory;/*** HuMan 产品父类* Interface HuMan* @package Luffy\DesignPatterns\Factory\AbstractFactory*/interface HuMan{/*** @return mixed*/public function say();}
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\AbstractFactory;/*** 具体产品类* Class Man* @package Luffy\DesignPatterns\Factory\AbstractFactory*/class Man implements HuMan{public function say(){echo "我是一个男人 👨 \n";}}
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\AbstractFactory;class WoMan implements HuMan{public function say(){echo "我是一个女人 👩 \n";}}
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\AbstractFactory;/*** Interface Monkey* @package Luffy\DesignPatterns\Factory\AbstractFactory*/interface Monkey{/*** @return mixed*/public function say();}
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\AbstractFactory;/*** 具体产品类* Class ApeMonkey* @package Luffy\DesignPatterns\Factory\AbstractFactory*/class ApeMonkey implements Monkey{public function say(){echo "我是一只猿猴 🐒 \n";}}
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\AbstractFactory;/*** Class FemaleMonkey* @package Luffy\DesignPatterns\Factory\AbstractFactory*/class FemaleMonkey implements Monkey{public function say(){echo "我是一只母猴 🐵 \n";}}
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/use Luffy\DesignPatterns\Factory\AbstractFactory\ManFactory;use Luffy\DesignPatterns\Factory\AbstractFactory\WoManFactory;include __DIR__ . '/../../vendor/autoload.php';class Client{public function index(){$factory = new ManFactory();$man = $factory->createHuMan();$man->say();$monkey = $factory->createMonkey();$monkey->say();echo "*****************\n";$factory = new WoManFactory();$woman = $factory->createHuMan();$woman->say();$woman_monkey = $factory->createMonkey();$woman_monkey->say();}}// 执行$demo = new Client;$demo->index();

不需要工厂子类了,只需要在工厂类中修改就好了
<?php/*** User: lufei* Date: 2019/9/16* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\OptimizeAbstractFactory;/*** Class Factory* @package Luffy\DesignPatterns\Factory\OptimizeAbstractFactory*/class Factory{public $create = "Man";public function __construct(){$config = include 'config.php';$this->create = $config['create'];}/*** @return mixed*/public function createHuMan(){switch ($this->create) {case 'Man':$human = new Man();break;case 'WoMan':$human = new WoMan();break;default:throw new \InvalidArgumentException("你是个什么 👿 人类?\n");}return $human;}/*** @return mixed*/public function createMonkey(){switch ($this->create) {case 'Man':$monkey = new ManMonkey();break;case 'WoMan':$monkey = new WoManMonkey();break;default:throw new \InvalidArgumentException("你是个什么 👿 猴子?\n");}return $monkey;}}

不需要工厂子类了,只需要在工厂类中修改就好了
<?php/*** User: lufei* Date: 2019/9/19* Email: lufei@swoole.com*/namespace Luffy\DesignPatterns\Factory\OptimizeAbstractFactory;use ReflectionClass;use ReflectionException;class FactoryWithReflection{/*** @var mixed|string*/public $create = "Man";/*** FactoryWithReflection constructor.*/public function __construct(){$config = include 'config1.php';$this->create = $config['create'];}/*** @return mixed*/public function createHuMan(){$className = __NAMESPACE__ .'\\'. $this->create;try {$class = new ReflectionClass($className);$human = $class->newInstance();} catch (ReflectionException $Exception) {throw new \InvalidArgumentException($Exception->getMessage());}return $human;}/*** @return mixed*/public function createMonkey(){$className = __NAMESPACE__ .'\\'. $this->create . "Monkey";try {$class = new ReflectionClass($className);$monkey = $class->newInstance();} catch (ReflectionException $Exception) {throw new \InvalidArgumentException($Exception->getMessage());}return $monkey;}}
服务容器中有两个概念控制反转(IOC)和依赖注入(DI):
依赖注入和控制反转是对同一件事情的不同描述,它们描述的角度不同。依赖注入是从应用程序的角度在描述,应用程序依赖容器创建并注入它所需要的外部资源。而控制反转是从容器的角度在描述,容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。
- IoC(控制反转)
- DI(依赖注入)
/*** 摘自Inspirer网站* https://www.insp.top/article/learn-laravel-container*/class Container{protected $binds;protected $instances;public function bind($abstract, $concrete){if ($concrete instanceof Closure) {$this->binds[$abstract] = $concrete;} else {$this->instances[$abstract] = $concrete;}}public function make($abstract, $parameters = []){if (isset($this->instances[$abstract])) {return $this->instances[$abstract];}array_unshift($parameters, $this);return call_user_func_array($this->binds[$abstract], $parameters);}}// 创建一个容器(后面称作超级工厂)$container = new Container;// 向该 超级工厂 添加 超人 的生产脚本$container->bind('superman', function($container, $moduleName) {return new Superman($container->make($moduleName));});// 向该 超级工厂 添加 超能力模组 的生产脚本$container->bind('xpower', function($container) {return new XPower;});// 同上$container->bind('ultrabomb', function($container) {return new UltraBomb;});// ****************** 华丽丽的分割线 **********************// 开始启动生产$superman_1 = $container->make('superman', ['xpower']);$superman_2 = $container->make('superman', ['ultrabomb']);$superman_3 = $container->make('superman', ['xpower']);
参考资料:
swoole微课堂
GitHub
类的反射和依赖注入
php.net反射(reflection)
Inspirer: laravel 学习笔记 —— 神奇的服务容器
服务容器(IocContainer)
php.net 类型约束
call_user_func_array