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下编码转换函数mb_convert_encoding与iconv的使用说明
Dec 16 PHP
解析php常用image图像函数集
Jun 24 PHP
解决cPanel无法安装php5.2.17
Jun 22 PHP
PHP中设置一个严格30分钟过期Session面试题的4种答案
Jul 30 PHP
php使用cookie保存用户登录的用户名实例
Jan 26 PHP
php基于单例模式封装mysql类完整实例
Oct 18 PHP
Laravel框架路由设置与使用示例
Jun 12 PHP
PHP里的$_GET数组介绍
Mar 22 PHP
PHP下用Swoole实现Actor并发模型的方法
Jun 12 PHP
php抽象方法和普通方法的区别点总结
Oct 13 PHP
CentOS7系统搭建LAMP及更新PHP版本操作详解
Mar 26 PHP
PHP数组Key强制类型转换实现原理解析
Sep 01 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生成html分页列表的代码
2007/03/18 PHP
php 模拟get_headers函数的代码示例
2013/04/27 PHP
ThinkPHP利用PHPMailer实现邮件发送实现代码
2013/09/26 PHP
php实现格式化多行文本为Js可用格式
2015/04/15 PHP
PHP基于rabbitmq操作类的生产者和消费者功能示例
2018/06/16 PHP
javascript 24小时弹出一次的代码(利用cookies)
2009/09/03 Javascript
用javascript读取xml文件读取节点数据
2014/08/12 Javascript
判断字符串的长度(优化版)中文占两个字符
2014/10/30 Javascript
Jquery实现图片预加载与延时加载的方法
2014/12/22 Javascript
JavaScript使用ActiveXObject访问Access和SQL Server数据库
2015/04/02 Javascript
使用jquery实现仿百度自动补全特效
2015/07/23 Javascript
使用coffeescript编写node.js项目的方法汇总
2015/08/05 Javascript
jQuery插件formValidator自定义函数扩展功能实例详解
2015/11/25 Javascript
JavaScript判断表单为空及获取焦点的方法
2016/02/12 Javascript
多功能jQuery树插件zTree实现权限列表简单实例
2016/07/12 Javascript
JS实现输入框提示文字点击时消失效果
2016/07/19 Javascript
BootStrap下拉菜单和滚动监听插件实现代码
2016/09/26 Javascript
jQuery Validate验证框架详解(推荐)
2016/12/17 Javascript
JQuery EasyUI的一些常用组件
2017/07/12 jQuery
axios全局注册,设置token,以及全局设置url请求网段的方法
2018/09/25 Javascript
Nodejs实现多文件夹文件同步
2018/10/17 NodeJs
原生JS实现烟花效果
2020/03/10 Javascript
Vue 根据条件判断van-tab的显示方式
2020/08/03 Javascript
常用python数据类型转换函数总结
2014/03/11 Python
Python中文编码知识点
2019/02/18 Python
Python中一些深不见底的“坑”
2019/06/12 Python
python修改FTP服务器上的文件名
2019/09/11 Python
Python爬虫使用代理IP的实现
2019/10/27 Python
PyQt5通过信号实现MVC的示例
2021/02/06 Python
中科创达面试题
2016/12/28 面试题
班组建设经验交流材料
2014/05/12 职场文书
项目经理岗位职责
2015/01/31 职场文书
2015年业务工作总结范文
2015/04/10 职场文书
主题班会开场白
2015/06/01 职场文书
预备党员党支部意见
2015/06/02 职场文书
剑指Offer之Java算法习题精讲二叉树专项训练
2022/03/21 Java/Android