目录

简单工厂模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?

就用到工厂方法模式,创建一个工厂接口和创建多个工厂实现类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。

代码示例

<?php

namespace DesignPattern;

/**
 * Description of AbstractFactoryDemo
 * 抽象工厂
 * @author jm
 */
class AbstractFactoryDemo
{
    /**
     * 入口方法
     */
    public static function main(){
        $channelData = [
            "name"=>"huawei",
            "appid"=>"xxxx"
        ];

        //方式1
        $channelObj = ChannelFactory::createChannel($channelData);
        $userModule = $channelObj->createUser();
        $userModule->login([]);
        $payModule = $channelObj->createPay();
        $payModule->order();
        $payModule->payCallback();        
        
//        //方式2
//        $channelObj = new Channel($channelData);
//        $userModule = ModuleFactory::createUserModule($channelObj);
//        $userModule->login([]);
//        $payModule = ModuleFactory::createPayModule($channelObj);
//        $payModule->order();
//        $payModule->payCallback();

    }
}


/**
 * 用户模块接口
 */
interface IUserModule{
    public function login($data);
}

/**
 * 支付模块接口
 */
interface IPayModule{
    public function order();
    public function payCallback();
}
//模块 父类
class Module{
    protected $channeObj = null;
    public function __construct($channelObj)
    {
        $this->channeObj = $channelObj;
    }
}
/**
 * 华为渠道用户模块
 */
class HuaweiUser extends Module implements IUserModule
{

    public function login($data)
    {
        echo "huawei Login success.".PHP_EOL;
        return "";
    }
}
/**
 * 华为渠道支付模块
 */
class HuaweiPay extends Module implements IPayModule
{

    public function order()
    {
        echo "huawei generate order.".PHP_EOL;
        
        return true;
    } 
    
    public function payCallback(){
       echo "huawei pay callback success.".PHP_EOL;
       return true;
    }
}
/**
 * 小米渠道用户模块
 */
class XiaomiUser extends Module implements IUserModule
{
  
    public function login($data)
    {
        echo "xiaomi Login success.".PHP_EOL;
        return "";
    }
}
/**
 * 小米渠道支付模块
 */
class XiaomiPay extends Module implements IPayModule
{
   
    public function order()
    {
        echo "xiaomi generate order.".PHP_EOL;
        
        return true;
    } 
    
    public function payCallback(){
       echo "xiaomi pay callback success.".PHP_EOL;
       return true;
    }
}
//
///**
// * 应用宝渠道用户模块
// */
//class YingyongbaoUser extends Module implements IUserModule
//{
//  
//    public function login($data)
//    {
//        echo "应用宝 Login success.".PHP_EOL;
//        return "";
//    }
//}
///**
// * 应用宝渠道支付模块
// */
//class YingyongbaoPay extends Module implements IPayModule
//{
//   
//    public function order()
//    {
//        echo "应用宝 generate order.".PHP_EOL;
//        
//        return true;
//    } 
//    
//    public function payCallback(){
//       echo "应用宝 pay callback success.".PHP_EOL;
//       return true;
//    }
//}

//渠道 父类
class Channel{
    private $_channelData = [];
    private $_channeName = 'xiaomi';
    public function __construct($channelData)
    {
        $this->_channelData = $channelData;
        $this->_channeName = $channelData['name'];
    }
    public function getChanneData(){
        return $this->_channelData;
    }
    public function getChannelName(){
        return $this->_channeName;
    }
}
//渠道接口 规约
interface IChannel{
    public  function createUser();
    public  function createPay();
}
//华为渠道
class Huawei extends Channel implements IChannel{
    public  function createUser(){
        return new HuaweiUser($this->getChanneData());
    }
    public  function createPay(){
        return new HuaweiPay($this->getChanneData());
    }  
}
//小米渠道
class Xiaomi extends Channel implements IChannel{
    public  function createUser(){
        return new XiaomiUser($this->getChanneData());
    }
    public  function createPay(){
        return new XiaomiPay($this->getChanneData());
    }     
}

////新增 应用宝渠道
//class Yingyongbao extends Channel implements IChannel{
//    public  function createUser(){
//        return new YingyongbaoUser($this->getChanneData());
//    }
//    public  function createPay(){
//        return new YingyongbaoPay($this->getChanneData());
//    }     
//}

//渠道工厂
class ChannelFactory{
    public static function createChannel($channelData){
        $className = "\\DesignPattern\\".ucfirst($channelData['name']);
        return new $className($channelData);
    }
}

////方式2
//class ModuleFactory{
//    public static function createUserModule($channelObj){
//        $className = "\\DesignPattern\\".ucfirst($channelObj->getChannelName())."User";
//        return new $className($channelObj);
//    }
//    public static function createPayModule($channelObj){
//        $className = "\\DesignPattern\\".ucfirst($channelObj->getChannelName())."Pay";
//        return new $className($channelObj);        
//    }
//}


AbstractFactoryDemo::main();


输出:

huawei Login success.
huawei generate order.
huawei pay callback success.

注:抽象工厂经常用在数据库模型上,有多种数据库(Oracle、mysql、sqlserver、MongoDB等),数据库有多种操作(连接、curd、表操作等)

工厂方法比对

工厂方法模式: 一个抽象产品类,可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类只能创建一个具体产品类的实例。

抽象工厂模式: 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类可以创建多个具体产品类的实例,也就是创建的是一个产品线下的多个产品。

区别: 工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。

工厂方法创建 “一种” 产品,他的着重点在于"怎么创建”,也就是说如果你开发,你的大量代码很可能围绕着这种产品的构造,初始化这些细节上面。也因为如此,类似的产品之间有很多可以复用的特征,所以会和模版方法相随。 

抽象工厂需要创建一些列产品,着重点在于"创建哪些"产品上,也就是说,如果你开发,你的主要任务是划分不同差异的产品线,并且尽量保持每条产品线接口一致,从而可以从同一个抽象工厂继承。

小结

抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们的具体类。

抽象工厂模式的好处便是易于交换产品系列,由于具体工厂类,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只是需要改变具体工厂即可使用不同的产品配置。它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操作实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户端代码中。


本文部分收藏来自互联网,仅用于学习研究,著作权归原作者所有,如有侵权请联系删除

markdown @TsingChan