实例讲解PHP设计模式编程中的简单工厂模式


Posted in PHP onFebruary 29, 2016

简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出那一种产品类的实例。

1.工厂模式的几种形态
工厂模式专门负责将大量有共同接口的类实例化。工厂模式可以动态决定将哪一个类实例化,不必事先知道每次要实例化哪一个类。工厂模式有以下几种形态:
(1)简单工厂(Simple Factory)模式,又称静态工厂方法模式(Static Factory Method Pattern)。
(2)工厂方法(Factory Method)模式,又称多态性工厂(Polymorphic Factory)模式或虚拟构造子(Virtual Constructor)模式;
(3)抽象工厂(Abstract Factory)模式,又称工具箱(Kit 或Toolkit)模式。下面就是简单工厂模式的简略类图。

简单工厂模式,或称静态工厂方法模式,是不同的工厂方法模式的一个特殊实现。在其他文献中,简单工厂往往作为普通工厂模式的一个特例讨论。
学习简单工厂模式是对学习工厂方法模式的一个很好的准备,也是对学习其他模式,特别是单例模式和多例模式的一个很好的准备。

2 .简单工厂模式的引进

比如说有一个农场公司,专门向市场销售各类水果。在这个系统里需要描述下列的水果:
葡萄 Grape
草莓 Strawberry
苹果 Apple
水果与其他的植物有很大的不同,就是水果最终是可以采摘食用的。那么一个自然的作法就是建立一个各种水果都适用的接口,以便与农场里的其他植物区分开。如下图所示。

水果接口规定出所有的水果必须实现的接口,包括任何水果类必须具备的方法:种植plant(),生长grow()以及收获harvest()。接口Fruit 的类图如下所示。

这个水果接口的源代码如下所示。
代码清单1:接口Fruit 的源代码

interface Fruit
{
public function grow();
public function harvest();
public function plant();
}

Apple 类是水果类的一种,因此它实现了水果接口所声明的所有方法。另外,由于苹果是多年生植物,因此多出一个treeAge 性质,描述苹果树的树龄。下面是这个苹果类的源代码。
代码清单2:类Apple 的源代码

class Apple implements Fruit
{
private $_treeAge;
public function grow()
{
echo "Apple is growing.";
}
public function harvest()
{
echo "Apple has been harvested.";
}
public function plant()
{
echo "Apple has been planted.";
}
public function getTreeAge()
{
return $this->_treeAge;
}
public function setTreeAge($treeAge)
{
$this->_treeAge = (int) $treeAge;
}
}

同样,Grape 类是水果类的一种,也实现了Fruit 接口所声明的所有的方法。但由于葡萄分有籽和无籽两种,因此,比通常的水果多出一个seedless 性质,如下图所示。

葡萄类的源代码如下所示。可以看出,Grape 类同样实现了水果接口,从而是水果类型的一种子类型。
代码清单3:类Grape 的源代码

class Grape implements Fruit
{
private $seedless;
public function grow()
{
echo "Grape is growing.";
}
public function harvest()
{
echo "Grape has been harvested.";
}
public function plant()
{
echo "Grape has been planted.";
}
public function getSeedless()
{
return $this->seedless;
}
public function setSeedless($seedless)
{
$this->seedless = (boolean) $seedless;
}
}

Strawberry 类实现了Fruit 接口,因此,也是水果类型的子类型,其源代码如下所示。
代码清单4:类Strawberry 的源代码

class Strawberry implements Fruit
{
public function grow()
{
echo "Strawberry is growing.";
}
public function harvest()
{
echo "Strawberry has been harvested.";
}
public function plant()
{
echo "Strawberry has been planted.";
}
}

农场的园丁也是系统的一部分,自然要由一个合适的类来代表。这个类就是FruitGardener 类,其结构由下面的类图描述。

FruitGardener 类会根据客户端的要求,创建出不同的水果对象,比如苹果(Apple),葡萄(Grape)或草莓(Strawberry)的实例。而如果接到不合法的要求,FruitGardener 类会抛出BadFruitException 异常。
园丁类的源代码如下所示。
代码清单5:FruitGardener 类的源代码

class FruitGardener
{
public static function factory($which)
{
$which = strtolower($which);
if ($which == 'apple') {
return new Apple();
} elseif ($which == 'strawberry') {
return new Strawberry();
} elseif ($which == 'grape') {
return new Grape();
} else {
throw new BadFruitException('Bad fruit request');
}
}
}

可以看出,园丁类提供了一个静态工厂方法。在客户端的调用下,这个方法创建客户端所需要的水果对象。如果客户端的请求是系统所不支持的,工厂方法就会抛出一个BadFruitException 异常。这个异常类的源代码如下所示。
代码清单6:BadFruitException 类的源代码

class BadFruitException extends Exception
{
}

在使用时,客户端只需调用FruitGardener 的静态方法factory()即可。请见下面的示意
性客户端源代码。
代码清单7:怎样使用异常类BadFruitException

try {
FruitGardener::factory('apple');
FruitGardener::factory('grape');
FruitGardener::factory('strawberry');
//...
} catch (BadFruitException $e) {
//...
}

这样,农场一定会百果丰收啦!

3.使用简单工厂模式设计一个“面向对象的”计算器

/**
 * 面向对象计算器
 * 思路:
 * 1、面向对象的基本,封装、继承、多太
 * 2、父类公用类
 * 3、各种运算类
 */
 
/**
 * 基类,运算类
 * 只提供基本数据,不参与运算
 */
 
class Operation {
  
 // 第一个数
 public $first_num = 0;
  
 // 第二个数
 public $second_num = 0;
  
 /**
  * 获取结果,其他类覆盖此方法
  * @return double $result
  */
 public function getResult() {
  $result = 0.00;
   
  return $result;
 }
}
 
/**
 * 加法类
 */
class OperationAdd extends Operation {
 /**
  * 覆盖父类,实现加法算法
  */
 public function getResult() {
  $result = 0;
  return $this->first_num + $this->second_num;
 }
}
 
/**
 * 减法类
 *
 */
class OperationSub extends Operation {
 /**
  * 覆盖父类,实现加法算法
  */
 public function getResult() {
  $result = 0;
  return $this->first_num - $this->second_num;
 }
}
 
/**
 * 乘法类
 *
 */
class OperationMul extends Operation {
 /**
  * 覆盖父类,实现加法算法
  */
 public function getResult() {
  $result = 0;
  return $this->first_num * $this->second_num;
 }
}
 
/**
 * 除类
 *
 */
class OperationDiv extends Operation {
 /**
  * 覆盖父类,实现加法算法
  */
 public function getResult() {
  $result = 0;
   
  if ($this->second_num == 0) {
   throw new Exception('除法操作第二个参数不能为零!');
   return 0;
  }
   
  return $this->first_num / $this->second_num;
 }
}
 
/**
 * 工厂类
 */
class OperationFactory {
 /**
  * 工厂函数
  * @param string $operation
  * @return object
  */
 public function createOperation($operation) {
  $oper = null;
   
  switch($operation) {
   case '+':
    $oper = new OperationAdd();
    break;
   case '-':
    $oper = new OperationSub();
    break;
   case '*':
    $oper = new OperationMul();
    break;
   case '/':
    $oper = new OperationDiv();
    break;
   default:
    return 0;
  }
  return $oper;
 }
}
 
 
$operation = new OperationFactory();
$oper = $operation->createOperation('/');
 
$oper->first_num = 10;
$oper->second_num = 20;
var_dump($oper->getResult());

实例讲解PHP设计模式编程中的简单工厂模式

PHP 相关文章推荐
开发大型PHP项目的方法
Oct 09 PHP
第七章 php自定义函数实现代码
Dec 30 PHP
PHP中3种生成XML文件方法的速度效率比较
Oct 06 PHP
探讨:web上存漏洞及原理分析、防范方法
Jun 29 PHP
推荐几个开源的微信开发项目
Dec 28 PHP
phpMyAdmin安装并配置允许空密码登录
Jul 04 PHP
PHP加密解密实例分析
Dec 25 PHP
CodeIgniter针对数据库的连接、配置及使用方法
Mar 03 PHP
PHP扩展框架之Yaf框架的安装与使用
May 18 PHP
PHP表单数据写入MySQL数据库的代码
May 31 PHP
Laravel5.5 动态切换多语言的操作方式
Oct 25 PHP
基于PHP的登录和注册的功能的实现
Aug 06 PHP
PHP Try-catch 语句使用技巧
Feb 28 #PHP
linux下为php添加iconv模块的方法
Feb 28 #PHP
PHP中模拟链表和链表的基本操作示例
Feb 27 #PHP
PHP使用Memcache时模拟命名空间及缓存失效问题的解决
Feb 27 #PHP
简单谈谈PHP中strlen 函数
Feb 27 #PHP
详解PHP的Laravel框架中Eloquent对象关系映射使用
Feb 26 #PHP
PHP文件缓存smarty模板应用实例分析
Feb 26 #PHP
You might like
无数据库的详细域名查询程序PHP版(5)
2006/10/09 PHP
7个超级实用的PHP代码片段
2011/07/11 PHP
在PHP中利用wsdl创建标准webservice的实现代码
2011/12/07 PHP
yii实现创建验证码实例解析
2014/07/31 PHP
分享php代码将360浏览器导出的favdb的sqlite数据库文件转换为html
2015/12/09 PHP
Yii实现文章列表置顶功能示例
2016/10/18 PHP
javascript显示隐藏层比较不错的方法分析
2008/09/30 Javascript
Firefox中beforeunload事件的实现缺陷浅析
2012/05/03 Javascript
JavaScript Array对象扩展indexOf()方法
2014/05/09 Javascript
Jquery 获取指定标签的对象及属性的设置与移除
2014/05/29 Javascript
Highcharts 多个Y轴动态刷新数据的实现代码
2016/05/28 Javascript
jQuery 3.0十大新特性
2016/07/06 Javascript
Asp.Net之JS生成分页条的方法
2016/11/23 Javascript
Vue 单文件中的数据传递示例
2017/03/21 Javascript
详解基于vue的移动web app页面缓存解决方案
2017/08/03 Javascript
JavaScript实现简单评论功能
2017/08/17 Javascript
微信小程序 input输入及动态设置按钮的实现
2017/10/27 Javascript
JavaScript实现表单注册、表单验证、运算符功能
2018/10/15 Javascript
解决vue更新路由router-view复用组件内容不刷新的问题
2019/11/04 Javascript
详解 javascript对象创建模式
2020/10/30 Javascript
对python mayavi三维绘图的实现详解
2019/01/08 Python
Python 生成一个从0到n个数字的列表4种方法小结
2019/11/28 Python
Python多重继承之菱形继承的实例详解
2020/02/12 Python
Python+Kepler.gl轻松制作酷炫路径动画的实现示例
2020/06/02 Python
python爬虫使用scrapy注意事项
2020/11/23 Python
Python爬虫之Selenium中frame/iframe表单嵌套页面
2020/12/04 Python
写一个在SQL Server创建表的SQL语句
2012/03/10 面试题
常见的软件开发流程有哪些
2015/11/14 面试题
环境科学毕业生自荐信
2013/11/21 职场文书
同学聚会老师邀请函
2014/01/28 职场文书
2014年清明节寄语
2014/04/03 职场文书
超市开店计划书
2014/04/26 职场文书
转让协议书
2015/01/27 职场文书
博士生专家推荐信
2015/03/25 职场文书
财务出纳岗位职责
2015/03/31 职场文书
交心谈心活动总结
2015/05/11 职场文书