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 相关文章推荐
Breeze 文章管理系统 v1.0.0正式发布
Dec 14 PHP
PHP学习 运算符与运算符优先级
Jun 15 PHP
从PHP $_SERVER相关参数判断是否支持Rewrite模块
Sep 26 PHP
检查用户名是否已在mysql中存在的php写法
Jan 20 PHP
php获取字段名示例分享
Mar 03 PHP
Codeigniter框架的更新事务(transaction)BUG及解决方法
Jul 25 PHP
PHP strip_tags保留多个HTML标签的方法
May 22 PHP
PHP CURL采集百度搜寻结果图片不显示问题的解决方法
Feb 03 PHP
如何修改Laravel中url()函数生成URL的根地址
Aug 11 PHP
PHP编译configure时常见错误的总结
Aug 17 PHP
TP5(thinkPHP5框架)实现显示错误信息及行号功能的方法
Jun 03 PHP
PHP判断一个变量是否为整数、正整数的方法示例
Sep 11 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
强烈推荐:php.ini中文版(2)
2006/10/09 PHP
PHP 递归效率分析
2009/11/24 PHP
php XPath对XML文件查找及修改实现代码
2011/07/27 PHP
PHP隐形一句话后门,和ThinkPHP框架加密码程序(base64_decode)
2011/11/02 PHP
深入PHP empty(),isset(),is_null()的实例测试详解
2013/06/06 PHP
php的SimpleXML方法读写XML接口文件实例解析
2014/06/16 PHP
如何判断php mysqli扩展类是否开启
2016/12/24 PHP
Yii2选项卡的简单使用
2017/05/26 PHP
实用javaScript技术-屏蔽类
2006/08/15 Javascript
JQuery 学习笔记 选择器之一
2009/07/23 Javascript
使用jquery实现select添加实现后台权限添加的效果
2011/05/28 Javascript
jQuery对Select的操作大集合(收藏)
2013/12/28 Javascript
ie浏览器使用js导出网页到excel并打印
2014/03/11 Javascript
javascript下拉框选项单击事件的例子分享
2015/03/04 Javascript
ECMAScript6块级作用域及新变量声明(let)
2015/06/12 Javascript
jquery实现全选、反选、获得所有选中的checkbox
2020/09/13 Javascript
checkbox:click事件触发span元素内容改变的方法
2017/09/11 Javascript
Node做中转服务器转发接口
2017/10/18 Javascript
vue 路由嵌套高亮问题的解决方法
2018/05/17 Javascript
jQuery实现提交表单时不提交隐藏div中input的方法
2019/10/08 jQuery
[02:53]DOTA2英雄基础教程 山岭巨人小小
2013/12/09 DOTA
python求斐波那契数列示例分享
2014/02/14 Python
Python中的装饰器用法详解
2015/01/14 Python
Python3.5装饰器原理及应用实例详解
2019/04/30 Python
Python 中@property的用法详解
2020/01/15 Python
Python selenium键盘鼠标事件实现过程详解
2020/07/28 Python
Python‘==‘ 及 ‘is‘相关原理解析
2020/09/05 Python
美国专营婴幼儿用品的购物网站:buybuy BABY
2017/01/01 全球购物
住房公积金接收函
2014/01/09 职场文书
校园达人秀策划书
2014/01/12 职场文书
大学活动邀请函
2014/01/28 职场文书
银行业务授权委托书
2014/10/10 职场文书
见习期个人总结
2015/03/05 职场文书
2015年社区综治宣传月活动总结
2015/03/25 职场文书
2019暑假阅读倡议书
2019/06/24 职场文书
Django开发RESTful API实现增删改查(入门级)
2021/05/10 Python