当前位置:首页 > PHP教程 > php高级应用 > 列表

一文读懂简单工厂、工厂方法、抽象工厂

发布:smiling 来源: PHP粉丝网  添加日期:2022-07-19 11:45:22 浏览: 评论:0 

基本上每个人手机里都有一款音乐播放器,目前流行的播放器有:QQ音乐、酷狗音乐、搜狗音乐、网易云音乐、天天动听等。下面是一段关于播放音乐的代码:

  1. if ($type == 'QQ') { 
  2.  
  3.     $player = new QQPlayer(); 
  4.  
  5. } else if ($type == 'Wy') { 
  6.  
  7.     $player = new WyPlayer(); 
  8.  
  9. } else if ($type == 'KG') { 
  10.  
  11.     $player = new KGPlayer(); 
  12.  
  13. } else { 
  14.  
  15.     $palyer = null; 
  16.  
  17. } 
  18.  
  19.    
  20.  
  21. $player->on();  // 打开播放器 
  22.  
  23. $player->choiceMusic('我不配');  // 选择歌曲 
  24.  
  25. $player->play();  // 开始播放 

为了时代码的逻辑更加清晰、可读性更好,我们要善于把功能独立的代码块封装成函数。按照这个设计思路,我们可以将其中的条件分支抽离出来,单独放在一个类中的方法中。这个类,我们就可以叫做简单工厂模式。

简单工厂模式的定义:一个类可以根据不同的参数来获取不同的实例,一般这些被创建的实例都具有相同的父类。

静态工厂模式:一般的,我们将简单工厂模式中的用于创建不同实例的方法设置为静态方法,避免创建多个相同实例。

下面我们用简单工厂模式改写上面的代码

  1. class MusicPlayerFactory 
  2.  
  3. { 
  4.  
  5.     public static function create ($type) 
  6.  
  7.     { 
  8.  
  9.         if ($type == 'QQ') { 
  10.  
  11.             $player = new QQPlayer(); 
  12.  
  13.         } else if ($type == 'Wy') { 
  14.  
  15.             $player = new WyPlayer(); 
  16.  
  17.         } else if ($type == 'KG') { 
  18.  
  19.             $player = new KGPlayer(); 
  20.  
  21.         } else { 
  22.  
  23.             $player = null; 
  24.  
  25.         } 
  26.  
  27.         return $player; 
  28.  
  29.     } 
  30.  
  31. } 
  32.  
  33. // 业务代码修改如下 
  34.  
  35. $player = MusicPlayerFactory:create('QQ'); 
  36.  
  37. $player->on();  // 打开播放器 
  38.  
  39. $player->choiceMusic('我不配');  // 选择歌曲 
  40.  
  41. $player->play();  // 开始播放 

对于上面的简单工厂模式,如果我们需要添加新的音乐播放器,就一定会修改MusicPlayerFactory的create方法,这有点不符合“开闭原则”。对于这种条件分支不是很多,另外类的创建也非常的简单,使用简单工厂模式是完全可以的。如果非要将if分支逻辑去掉,使他符合“开闭原则”,那么就可以使用工厂方法来实现。对于工厂方法,也不是一定比简单工厂模式要好,虽然它的扩展性比较好,但是牺牲了可读性。

工厂方法模式

定义:在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。

现在我们用“多态”来消除掉上面简单工厂模式的if分支结构。实现的代码如下所示:

  1. interface IMusicPlayerFactory 
  2.  
  3. { 
  4.  
  5.     static function create (); 
  6.  
  7. } 
  8.  
  9.  
  10.  
  11. class QQPlayerFactory implements IMusicPlayerFactory 
  12.  
  13. { 
  14.  
  15.     public static function create () 
  16.  
  17.     { 
  18.  
  19.         return new QQPlayer(); 
  20.  
  21.     } 
  22.  
  23. } 
  24.  
  25.  
  26.  
  27. class WyPlayerFactory implements IMusicPlayerFactory 
  28.  
  29. { 
  30.  
  31.     public static function create () 
  32.  
  33.     { 
  34.  
  35.         return new WyPlayer(); 
  36.  
  37.     } 
  38.  
  39. } 
  40.  
  41.  
  42.  
  43. class KGPlayerFactory implements IMusicPlayerFactory 
  44.  
  45. { 
  46.  
  47.     public static function create () 
  48.  
  49.     { 
  50.  
  51.         return new KGPlayer(); 
  52.  
  53.     } 
  54.  
  55. } 
  56.  
  57.  
  58.  
  59. // 业务代码修改如下 
  60.  
  61. if ($type == 'QQ') { 
  62.  
  63.     $player = QQPlayerFactory::create(); 
  64.  
  65. } else if ($type == 'Wy') { 
  66.  
  67.     $player = WyPlayerFactory::create(); 
  68.  
  69. } else if ($type == 'KG') { 
  70.  
  71.     $player = KGPlayerFactory::create(); 
  72.  
  73. } else { 
  74.  
  75.     throw new \Exception('...'); 
  76.  
  77. } 
  78.  
  79. $player->on();  // 打开播放器 
  80.  
  81. $player->choiceMusic('我不配');  // 选择歌曲 
  82.  
  83. $player->play();  // 开始播放 

可以看到,问题又回到了原点,业务代码里又出现了if条件分支结构。那么怎么去解决该问题呢?

我们可以为工厂类再创建一个简单工厂,用来创建工厂类对象。新的简单工厂代码如下:

  1. class MusicPlayerFactoryMap 
  2.  
  3. { 
  4.  
  5.     const Players = [ 
  6.  
  7.         'QQ' => 'QQPlayerFactory', 
  8.  
  9.         'Wy' => 'WyPlayerFactory', 
  10.  
  11.         'KG' => 'KGPlayerFactory' 
  12.  
  13.     ]; 
  14.  
  15.     public static function getPlayerFactory (string $type) 
  16.  
  17.     { 
  18.  
  19.         if (emptyempty($type)) { 
  20.  
  21.             return null; 
  22.  
  23.         } 
  24.  
  25.         return (self::Players[$type])::create(); 
  26.  
  27.     } 
  28.  
  29. } 
  30.  
  31.  
  32.  
  33. // 业务代码修改如下 
  34.  
  35. $palyer = MusicPlayerFactoryMap::getPlayerFactory('QQ') 
  36.  
  37. $player->on();  // 打开播放器 
  38.  
  39. $player->choiceMusic('我不配');  // 选择歌曲 
  40.  
  41. $player->play();  // 开始播放 

可以看到,使用了工厂模式,结构变的比之前复杂的多。如果来的创建实例过程复制,我们才会推荐使用工厂方法模式。

抽象工厂模式

抽象工厂模式使用场景比较特殊,用的比较少。在工厂方法模式中,具体工厂负责生产具体的产品,每一个工厂对应一个具体产品。但有时候,我们需要一个工厂可以创建多个产品对象,而不是一个单一的产品。

我们用一个例子来看看:对象电脑厂是负责生产电脑来出售的。我们知道,电脑是由主机、键盘、显示器以及鼠标组成的,目前对象电脑城只生产3种电脑,低配、中配和高配的,不同配置的电脑使用的主机品牌、显示器品牌等都是不同的。

主机目前有:麒麟主机、雷霆主机、冬日主机

键盘目前有:雷柏、罗技、雷蛇

显示器目前有:aoc、hkc、BenQ

鼠标目前有:罗技、灵蛇、方正

顶配版电脑由麒麟主机、雷柏键盘、aoc显示器、罗技鼠标组成,中配由……。

关于主机的代码如下:

  1. interface Host 
  2.  
  3. { 
  4.  
  5.     static function createHost (); 
  6.  
  7. } 
  8.  
  9. class DrHost implements Host 
  10.  
  11. { 
  12.  
  13.     public static function createHost() 
  14.  
  15.     { 
  16.  
  17.         echo '创建冬日主机' . PHP_EOL; 
  18.  
  19.     } 
  20.  
  21. } 
  22.  
  23. class QlHost implements Host 
  24.  
  25. { 
  26.  
  27.     public static function createHost() 
  28.  
  29.     { 
  30.  
  31.         echo '创建麒麟主机' . PHP_EOL; 
  32.  
  33.     } 
  34.  
  35. } 
  36.  
  37. class LtHost implements Host 
  38.  
  39. { 
  40.  
  41.     public static function createHost() 
  42.  
  43.     { 
  44.  
  45.         echo '创建雷霆主机' . PHP_EOL; 
  46.  
  47.     } 
  48.  
  49. } 

类似的,去创建键盘、显示器、鼠标,代码这里就不贴了。

现在,我们定义一个创建电脑的接口。

  1. interface ComputerFactory 
  2.  
  3. { 
  4.  
  5.     static function createHost (); 
  6.  
  7.     static function createKeyboard (); 
  8.  
  9.     static function createMonitor (); 
  10.  
  11.     static function createMouse (); 
  12.  
  13. } 

然后完成三个具体工厂用于创建低配、中配以及高配版电脑。

  1. class GreatComputerFactory implements ComputerFactory 
  2.  
  3. { 
  4.  
  5.     public static function createHost() 
  6.  
  7.     { 
  8.  
  9.         QlHost::createHost(); 
  10.  
  11.     } 
  12.  
  13.     public static function createKeyboard() 
  14.  
  15.     { 
  16.  
  17.         LbKeyboard::createKeyboard(); 
  18.  
  19.     } 
  20.  
  21.     public static function createMonitor() 
  22.  
  23.     { 
  24.  
  25.         AocMonitor::createMonitor(); 
  26.  
  27.     } 
  28.  
  29.     public static function createMouse() 
  30.  
  31.     { 
  32.  
  33.         LjMouse::createMouse(); 
  34.  
  35.     } 
  36.  
  37. } 
  38.  
  39. class GoodComputerFactory implements ComputerFactory 
  40.  
  41. { 
  42.  
  43.     public static function createHost() 
  44.  
  45.     { 
  46.  
  47.         LtHost::createHost(); 
  48.  
  49.     } 
  50.  
  51.     public static function createKeyboard() 
  52.  
  53.     { 
  54.  
  55.         LjKeyboard::createKeyboard(); 
  56.  
  57.     } 
  58.  
  59.     public static function createMonitor() 
  60.  
  61.     { 
  62.  
  63.         HkcMonitor::createMonitor(); 
  64.  
  65.     } 
  66.  
  67.     public static function createMouse() 
  68.  
  69.     { 
  70.  
  71.         LsMouse::createMouse(); 
  72.  
  73.     } 
  74.  
  75. } 
  76.  
  77. class NormalComputerFactory implements ComputerFactory 
  78.  
  79. { 
  80.  
  81.     public static function createHost() 
  82.  
  83.     { 
  84.  
  85.         DrHost::createHost(); 
  86.  
  87.     } 
  88.  
  89.     public static function createKeyboard() 
  90.  
  91.     { 
  92.  
  93.         LsKeyboard::createKeyboard(); 
  94.  
  95.     } 
  96.  
  97.     public static function createMonitor() 
  98.  
  99.     { 
  100.  
  101.         BenqMonitor::createMonitor(); 
  102.  
  103.     } 
  104.  
  105.     public static function createMouse() 
  106.  
  107.     { 
  108.  
  109.         FzMouse::createMouse(); 
  110.  
  111.     } 
  112.  
  113. } 

现在可以来创建具体的电脑了

  1. class GreatComputer 
  2.  
  3. { 
  4.  
  5.     public function __construct() 
  6.  
  7.     { 
  8.  
  9.         echo '高配电脑' . PHP_EOL; 
  10.  
  11.         GreatComputerFactory::createHost(); 
  12.  
  13.         GreatComputerFactory::createKeyboard(); 
  14.  
  15.         GreatComputerFactory::createMonitor(); 
  16.  
  17.         GreatComputerFactory::createMouse(); 
  18.  
  19.     } 
  20.  
  21. } 
  22.  
  23. class GoodComputer 
  24.  
  25. { 
  26.  
  27.     public function __construct() 
  28.  
  29.     { 
  30.  
  31.         echo '中配电脑' . PHP_EOL; 
  32.  
  33.         GoodComputerFactory::createHost(); 
  34.  
  35.         GoodComputerFactory::createKeyboard(); 
  36.  
  37.         GoodComputerFactory::createMonitor(); 
  38.  
  39.         GoodComputerFactory::createMouse(); 
  40.  
  41.     } 
  42.  
  43. } 
  44.  
  45. class NormalComputer 
  46.  
  47. { 
  48.  
  49.     public function __construct() 
  50.  
  51.     { 
  52.  
  53.         echo '低配电脑' . PHP_EOL; 
  54.  
  55.         NormalComputerFactory::createHost(); 
  56.  
  57.         NormalComputerFactory::createKeyboard(); 
  58.  
  59.         NormalComputerFactory::createMonitor(); 
  60.  
  61.         NormalComputerFactory::createMouse(); 
  62.  
  63.     } 
  64.  
  65. }

Tags: 简单工厂 工厂方法 抽象工厂

分享到:

相关文章