@Chiang
2019-12-11T18:46:09.000000Z
字数 11897
阅读 669
设计模式
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