简单工厂模式

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

if ($type == 'QQ') {    $player = new QQPlayer();} else if ($type == 'Wy') {    $player = new WyPlayer();} else if ($type == 'KG') {    $player = new KGPlayer();} else {    $palyer = null;} $player->on();  // 打开播放器$player->choiceMusic('我不配');  // 选择歌曲$player->play();  // 开始播放

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

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

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

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

class MusicPlayerFactory{    public static function create ($type)    {        if ($type == 'QQ') {            $player = new QQPlayer();        } else if ($type == 'Wy') {            $player = new WyPlayer();        } else if ($type == 'KG') {            $player = new KGPlayer();        } else {            $player = null;        }        return $player;    }}// 业务代码修改如下$player = MusicPlayerFactory:create('QQ');$player->on();  // 打开播放器$player->choiceMusic('我不配');  // 选择歌曲$player->play();  // 开始播放

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

工厂方法模式

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

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

interface IMusicPlayerFactory{    static function create ();}class QQPlayerFactory implements IMusicPlayerFactory{    public static function create ()    {        return new QQPlayer();    }}class WyPlayerFactory implements IMusicPlayerFactory{    public static function create ()    {        return new WyPlayer();    }}class KGPlayerFactory implements IMusicPlayerFactory{    public static function create ()    {        return new KGPlayer();    }}// 业务代码修改如下if ($type == 'QQ') {    $player = QQPlayerFactory::create();} else if ($type == 'Wy') {    $player = WyPlayerFactory::create();} else if ($type == 'KG') {    $player = KGPlayerFactory::create();} else {    throw new \Exception('...');}$player->on();  // 打开播放器$player->choiceMusic('我不配');  // 选择歌曲$player->play();  // 开始播放

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

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

class MusicPlayerFactoryMap{    const Players = [        'QQ' => 'QQPlayerFactory',        'Wy' => 'WyPlayerFactory',        'KG' => 'KGPlayerFactory'    ];    public static function getPlayerFactory (string $type)    {        if (empty($type)) {            return null;        }        return (self::Players[$type])::create();    }}// 业务代码修改如下$palyer = MusicPlayerFactoryMap::getPlayerFactory('QQ')$player->on();  // 打开播放器$player->choiceMusic('我不配');  // 选择歌曲$player->play();  // 开始播放

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

抽象工厂模式

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

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

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

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

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

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

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

关于主机的代码如下:

interface Host{    static function createHost ();}class DrHost implements Host{    public static function createHost()    {        echo '创建冬日主机' . PHP_EOL;    }}class QlHost implements Host{    public static function createHost()    {        echo '创建麒麟主机' . PHP_EOL;    }}class LtHost implements Host{    public static function createHost()    {        echo '创建雷霆主机' . PHP_EOL;    }}

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

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

interface ComputerFactory{    static function createHost ();    static function createKeyboard ();    static function createMonitor ();    static function createMouse ();}

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

class GreatComputerFactory implements ComputerFactory{    public static function createHost()    {        QlHost::createHost();    }    public static function createKeyboard()    {        LbKeyboard::createKeyboard();    }    public static function createMonitor()    {        AocMonitor::createMonitor();    }    public static function createMouse()    {        LjMouse::createMouse();    }}class GoodComputerFactory implements ComputerFactory{    public static function createHost()    {        LtHost::createHost();    }    public static function createKeyboard()    {        LjKeyboard::createKeyboard();    }    public static function createMonitor()    {        HkcMonitor::createMonitor();    }    public static function createMouse()    {        LsMouse::createMouse();    }}class NormalComputerFactory implements ComputerFactory{    public static function createHost()    {        DrHost::createHost();    }    public static function createKeyboard()    {        LsKeyboard::createKeyboard();    }    public static function createMonitor()    {        BenqMonitor::createMonitor();    }    public static function createMouse()    {        FzMouse::createMouse();    }}

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

class GreatComputer{    public function __construct()    {        echo '高配电脑' . PHP_EOL;        GreatComputerFactory::createHost();        GreatComputerFactory::createKeyboard();        GreatComputerFactory::createMonitor();        GreatComputerFactory::createMouse();    }}class GoodComputer{    public function __construct()    {        echo '中配电脑' . PHP_EOL;        GoodComputerFactory::createHost();        GoodComputerFactory::createKeyboard();        GoodComputerFactory::createMonitor();        GoodComputerFactory::createMouse();    }}class NormalComputer{    public function __construct()    {        echo '低配电脑' . PHP_EOL;        NormalComputerFactory::createHost();        NormalComputerFactory::createKeyboard();        NormalComputerFactory::createMonitor();        NormalComputerFactory::createMouse();    }}

更多相关文章

  1. 一文读懂php设计模式之代理模式
  2. 一文读懂php设计模式之责任链模式
  3. 一文读懂php设计模式之模板方法模式
  4. php的设计模式是什么意思
  5. 什么是php工厂模式
  6. PHP——MVC模式讲解与实例

随机推荐

  1. iphone Android JS的使用
  2. Android项目发布 ---- Jcenter篇
  3. android为文本框设置背景资源-shape
  4. Android简易实战教程--第三十九话《Chron
  5. .Net 转战 Android 4.4 日常笔记(5)--新软
  6. 小胖加入Android Fans的 大军了 呵呵
  7. 在android的java代码中自定义log
  8. Android热修复(一):底层替换、类加载原理总
  9. Android(安卓)长按电源键关机整个流程小
  10. 松下将在日本推出 7 寸和 10 寸企业用三