PHP设计模式之工厂模式(Factory Pattern)的讲解


Posted in PHP onMarch 21, 2019

面向对象编程中,工厂模式是我们最常用的实例化对象模式,工厂类就是一个专门用来创建其它对象的类,工厂类在多态性编程实践中是非常重要的。它允许动态替换类,修改配置,会使应用程序更加灵活。掌握工厂模式对Web开发是必不可少的,它会给你的系统带来更大的可扩展性和尽量少的修改量。

工厂模式通常用来返回类似接口的不同的类,工厂的一种常见用法就是创建多态的提供者。

通常工厂模式有一个关键的构造,即一般被命名为factory的静态方法。这个静态方法可以接受任意数量的参数,并且必须返回一个对象。

一个非常贴近生活的例子来告诉你什么是工厂模式

但是工厂模式真的是个累赘吗?其实并不是!他能够作为一种设计模式流传至今,一定是有他的道理的!只不过我们看到的例子只能说明工厂模式是什么,并不能很好说明工厂模式的优点,所以我们学会后并不知道为什么要使用工厂模式,以及什么时候应该去使用工厂模式!

其实工厂模式在我们的现实生活中非常常见,下面我举个生活中的例子,大家应该就能明白工厂模式的用处在哪里了!

麦当劳大家都吃过吧?我们去点餐的时候,我们可以点一个汉堡,一杯可乐,一个薯条。我们还可以点一杯可乐,一个薯条。点完之后点餐员会问我们一句还要别的吗?你说不要了! 然后你的这一份餐就点完了,可以给钱了。咦,我们发现这是一个建造者模式(Builder Pattern)啊!

(ps:这确实是突然发现的,之前写建造者模式那篇文章的时候并没有想到这个例子)

基本的工厂类:

<?php
 class Fruit {
 // 对象从工厂类返回
 }
 Class FruitFactory {
 public static function factory() {
  // 返回对象的一个新实例
  return new Fruit();
 }
 }
 // 调用工厂
 $instance = FruitFactory::factory();
?>

利用工厂类生产对象:

<?php
class Example
{
  // The parameterized factory method
  public static function factory($type)
  {
    if (include_once 'Drivers/' . $type . '.php') {
      $classname = 'Driver_' . $type;
      return new $classname;
    } else {
      throw new Exception('Driver not found');
    }
  }
}
// Load a MySQL Driver
$mysql = Example::factory('MySQL');
// Load an SQLite Driver
$sqlite = Example::factory('SQLite');
?>

一个完整的工厂类:

下面的程序定义了一个通用的工厂类,它生产能够保存你所有操作的空对象,你可以获得一个实例,这些操作都在那个实例中了。

<?php
  /**
   * Generic Factory class
   * This Factory will remember all operations you perform on it,
   * and apply them to the object it instantiates.
   */
  class FruitFactory {
    private $history, $class, $constructor_args;
    /**
     * Create a factory of given class. Accepts extra arguments to be passed to
     * class constructor.
     */
    function __construct( $class ) {
      $args = func_get_args();
      $this->class = $class;
      $this->constructor_args = array_slice( $args, 1 );
    }
    function __call( $method, $args ) {
      $this->history[] = array(
        'action'  => 'call',
        'method'  => $method,
        'args'  => $args
      );
    }
    function __set( $property, $value ) {
      $this->history[] = array(
        'action'  => 'set',
        'property'  => $property,
        'value'    => $value
      );
    }
    /**
     * Creates an instance and performs all operations that were done on this MagicFactory
     */
    function instance() {
      # use Reflection to create a new instance, using the $args 
      $reflection_object = new ReflectionClass( $this->class ); 
      $object = $reflection_object->newInstanceArgs( $this->constructor_args ); 
      # Alternative method that doesn't use ReflectionClass, but doesn't support variable
      # number of constructor parameters.
      //$object = new $this->class();
      # Repeat all remembered operations, apply to new object.
      foreach( $this->history as $item ) {
        if( $item['action'] == 'call' ) {
          call_user_func_array( array( $object, $item['method'] ), $item['args'] );
        }
        if( $item['action'] == 'set' ) {
          $object->{$item['property']} = $item['value'];
        }
      }
      # Done
      return $object;
    }
  }
  class Fruit {
    private $name, $color;
    public $price;
    function __construct( $name, $color ) {
      $this->name = $name;
      $this->color = $color;
    }
    function setName( $name ) {
      $this->name = $name;
    }
    function introduce() {
      print "Hello, this is an {$this->name} {$this->sirname}, its price is {$this->price} RMB.";
    }
  }
  # Setup a factory
  $fruit_factory = new FruitFactory('Fruit', 'Apple', 'Gonn');
  $fruit_factory->setName('Apple');
  $fruit_factory->price = 2;
  # Get an instance
  $apple = $fruit_factory->instance();
  $apple->introduce();
?>

工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。

工厂模式可以分为三类:

  • 简单工厂模式(Simple Factory)
  • 工厂方法模式(Factory Method)
  • 抽象工厂模式(Abstract Factory)

这三种模式从上到下逐步抽象,并且更具一般性。

简单工厂模式又称静态工厂方法模式;从命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。

工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。

工厂方法模式仿佛已经很完美的对对象的创建进行了包装,使得客户程序中仅仅处理抽象产品角色提供的接口。那我们是否一定要在代码中遍布工厂呢?大可不必。也许在下面情况下你可以考虑使用工厂方法模式:

  • 当客户程序不需要知道要使用对象的创建过程。
  • 客户程序使用的对象存在变动的可能,或者根本就不知道使用哪一个具体的对象。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。如果你想了解更多相关内容请查看下面相关链接

PHP 相关文章推荐
PHP的历史和优缺点
Oct 09 PHP
QQ登录 PHP OAuth示例代码
Jul 20 PHP
php调用nginx的mod_zip模块打包ZIP文件
Jun 11 PHP
ThinkPHP标签制作教程
Jul 10 PHP
简单说说PHP优化那些事(经验分享)
Nov 27 PHP
php下pdo的mysql事务处理用法实例
Dec 27 PHP
PHP实现上传文件并存进数据库的方法
Jul 16 PHP
laravel自定义分页效果
Jul 23 PHP
php封装单文件上传到数据库(路径)
Oct 15 PHP
swoole和websocket简单聊天室开发
Nov 18 PHP
laravel http 自定义公共验证和响应的方法
Sep 29 PHP
Yii框架的redis命令使用方法简单示例
Oct 15 PHP
使用PHP反射机制来构造&quot;CREATE TABLE&quot;的sql语句
Mar 21 #PHP
启用OPCache提高PHP程序性能的方法
Mar 21 #PHP
Discuz不使用插件实现简单的打赏功能
Mar 21 #PHP
PHP+RabbitMQ实现消息队列的完整代码
Mar 20 #PHP
PHP实现的数据对象映射模式详解
Mar 20 #PHP
PHP单例模式数据库连接类与页面静态化实现方法
Mar 20 #PHP
PHP实现的策略模式示例
Mar 20 #PHP
You might like
全新Mac配置PHP开发环境教程
2016/02/03 PHP
php面向对象的用户登录身份验证
2017/06/08 PHP
PHP设计模式之模板模式定义与用法详解
2018/12/20 PHP
php 使用ActiveMQ发送消息,与处理消息操作示例
2020/02/23 PHP
jQuery EasyUI API 中文文档 - Menu菜单
2011/10/03 Javascript
利用JavaScript实现新闻滚动效果(实例代码)
2013/11/27 Javascript
js实现随屏幕滚动的带缓冲效果的右下角广告代码
2015/09/04 Javascript
基于RequireJS和JQuery的模块化编程——常见问题全面解析
2016/04/14 Javascript
Javascript 实现简单计算器实例代码
2016/10/23 Javascript
JS实现随机颜色的3种方法与颜色格式的转化
2017/01/05 Javascript
移动端触摸滑动插件swiper使用方法详解
2017/08/11 Javascript
微信小程序textarea层级过高(盖住其他元素)问题的解决办法
2019/03/04 Javascript
VUE脚手架的下载和配置步骤详解
2019/04/01 Javascript
基于JS实现前端压缩上传图片的实例代码
2019/05/14 Javascript
Element-UI中关于table表格的那些骚操作(小结)
2019/08/15 Javascript
layui按条件隐藏表格列的实例
2019/09/19 Javascript
基于js判断浏览器是否支持webGL
2020/04/18 Javascript
[46:48]DOTA2上海特级锦标赛A组小组赛#2 Secret VS CDEC第三局
2016/02/25 DOTA
[00:37]食人魔魔法师轮盘吉兆顺应全新至宝将拥有额外款式
2019/12/19 DOTA
Python将xml和xsl转换为html的方法
2015/03/10 Python
Python 多维List创建的问题小结
2019/01/18 Python
python监控进程状态,记录重启时间及进程号的实例
2019/07/15 Python
Python字典常见操作实例小结【定义、添加、删除、遍历】
2019/10/25 Python
Python闭包与装饰器原理及实例解析
2020/04/30 Python
Python3爬虫关于识别检验滑动验证码的实例
2020/07/30 Python
玩具反斗城葡萄牙官方商城:Toys"R"Us葡萄牙
2016/10/21 全球购物
四方通行旅游网:台湾订房、出国旅游
2017/09/20 全球购物
澳大利亚一站式数码相机商店:CameraPro
2020/03/09 全球购物
将"引用"作为函数参数有哪些特点
2013/04/05 面试题
六十岁生日答谢词
2014/01/10 职场文书
自主实习接收函
2014/01/13 职场文书
2014年最新个人对照检查材料范文
2014/09/25 职场文书
2015年仓库工作总结
2015/04/09 职场文书
关于公司年会的开幕词
2016/03/04 职场文书
golang在GRPC中设置client的超时时间
2021/04/27 Golang
python在package下继续嵌套一个package
2022/04/14 Python