【设计模式】简单工厂模式

引入

简单工厂模式(Simple Factory)属于设计模式中的创建型模式。简单设计模式实际上不属于23个Gof(Gang of Four)模式之一,这里介绍简单模式,是作为我们下一步学习有点难度的GoF模式之一的工厂方法(Factory Method)的入门。

简单工厂模式根据提供的数据返回几个可能的类中的一个实例。通常返回的类都有一个共同的父类和一些共同的方法。只不过这些类中的每一个都完成不同的任务,以及针对不同的类型数据进行处理。

简单工厂如何工作

我们来看一下下面的这个类图:

简单工厂模式

图: 简单工厂模式

图中 X 是基类,XY 和 XZ都继承自 X,XFactory 根据提供的参数来决定返回这些子类中的哪一个。在XFactory类中,我们定义了一个 getClass 方法,该方法根据传入的值,来返回X两个子类中的其中一个实例,返回的是哪一个类的实例对于开发者来说并不重要,因为这些类都有着相同的方法,只是实现不同而已。返回哪一个实例完全取决于工厂。

示例代码

考虑下这样的一个情景,在注册页面中,我们希望允许用户以”名字 姓氏“ 或者是 ”姓氏,名字“这样的格式输入他的姓名,为了演示简单,我们假设可以通过判断姓氏和名字之间是否有逗号来确定姓名的顺序。

首先我们可以使用一个叫做 “FirstFirst”的类来处理 “名字 姓氏”这种格式的姓名,用一个叫做“LastFirst”的类来处理”姓氏,名字“这种格式的姓名。这两个类有个共同的目的,就是分别取出姓氏和名字。这样我们可以先定义一个简单的类:Namer,Namer这个类有两个属性,分别是frName和lName,分别存储first name 和 last name,同时Namer类还有两个方法 getFrname 和 getLname ,分别用来获取名字和姓氏,我们使用这个类作为FirstFirst类和LastFirst类的基类。

姓名工厂程序

图:姓名工厂程序

  1. <?php
  2.  
  3. /**
  4.  * 分割姓名的基类
  5.  * Created by PhpStorm.
  6.  * User: AppDays
  7.  * Date: 2017/2/12
  8.  * Time: 23:03
  9.  */
  10. class Namer
  11. {
  12.     //名字
  13.     protected $frName;
  14.     //姓氏
  15.     protected $lName;
  16.     //返回名字
  17.     public function getFrname(){
  18.         return $this->frName;
  19.     }
  20.     //返回姓氏
  21.     public function getLname(){
  22.         return $this->lName;
  23.     }
  24.  
  25.  
  26. }

然后是两个派生类 FirstFirst 和 LastFirst:

  1. <?php
  2.  
  3. /**
  4.  * 用来处理FirstFirst类型的姓名
  5.  * Created by PhpStorm.
  6.  * User: AppDays
  7.  * Date: 2017/2/12
  8.  * Time: 23:15
  9.  */
  10. include_once "Namer.php";
  11. class FirstFirst extends Namer
  12. {
  13.  
  14.     function __construct($name){
  15.         $name =trim($name);
  16.         $i = strpos($name,' ');
  17.         if($i>0) {
  18.             $this->frName = substr($name, 0, $i);
  19.             $this->lName = substr($name, $i+1);
  20.         }else{
  21.             $this->lName=$name;
  22.             $this->frName="";
  23.         }
  24.     }
  25.  
  26. }
  1. <?php
  2.  
  3. /**
  4.  * 用来处理LastFirst类型的姓名
  5.  * Created by PhpStorm.
  6.  * User: AppDays
  7.  * Date: 2017/2/13
  8.  * Time: 20:54
  9.  */
  10. include_once "Namer.php";
  11. class LastFirst extends Namer
  12. {
  13.     function __construct($name){
  14.         $name =trim($name);
  15.         $i = strpos($name,',');
  16.         if($i>0){
  17.             $this->lName = substr($name,0,$i);
  18.             $this->frName=substr($name,$i+1);
  19.         }else{
  20.             $this->lName=$name;
  21.             $this->frName='';
  22.         }
  23.     }
  24.  
  25. }

构建简单工厂类

工厂类的实现也很简单,只需要有个方法,比如 getName ,接收不同写法的姓名,然后根据判断姓名中是否有逗号来返回FirstFirst和LastFirst两个类中的其中一个实例就可以了。

  1. <?php
  2.  
  3. /**
  4.  * 工厂类
  5.  * Created by PhpStorm.
  6.  * User: AppDays
  7.  * Date: 2017/2/13
  8.  * Time: 20:57
  9.  */
  10. include_once "LastFirst.php";
  11. include_once "FirstFirst.php";
  12. class NameFactory
  13. {
  14.     public function getName($name){
  15.         $i = strpos($name,',');
  16.         if($i){
  17.             return new LastFirst($name);
  18.         }else{
  19.             return new FirstFirst($name);
  20.         }
  21.     }
  22.  
  23. }

使用工厂

我们新建一个index.php页面,分别定义两种不同写法的姓名,然后使用工厂类的实例获取到每种不同写法姓名的姓氏和名字。

  1. <?php
  2. /**
  3.  * Created by PhpStorm.
  4.  * User: AppDays
  5.  * Date: 2017/2/13
  6.  * Time: 21:00
  7.  */
  8. include "NameFactory.php";
  9. //创建一个工厂类的实例
  10. $nameFactory = new NameFactory();
  11. //firstfirst
  12. $name1 = 'App Days';
  13. //lastfirst
  14. $name2 ='Days,App';
  15.  
  16. $namer1= $nameFactory->getName($name1);
  17.  
  18. $namer2 =$nameFactory->getName($name2);
  19.  
  20. echo "Enter name :$name1;First name:{$namer1->getFrname()};Last name:{$namer1->getLname()};</br>";
  21. echo "Enter name :$name2;First name:{$namer2->getFrname()};Last name:{$namer2->getLname()};</br>";

OK,在index页面中,我们不需要知道 FirstFirst 和 LastFirst 两个类和它们各自的实现,我们只需要创建一个工厂实例,然后传入我们不同写法的姓名,就可以获取到姓氏和名字了。

QQ截图20170213230308