一文读懂简单工厂、工厂方法、抽象工厂
简单工厂模式
基本上每个人手机里都有一款音乐播放器,目前流行的播放器有: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(); } }
以上是一文读懂简单工厂、工厂方法、抽象工厂的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

会话劫持可以通过以下步骤实现:1.获取会话ID,2.使用会话ID,3.保持会话活跃。在PHP中防范会话劫持的方法包括:1.使用session_regenerate_id()函数重新生成会话ID,2.通过数据库存储会话数据,3.确保所有会话数据通过HTTPS传输。

SOLID原则在PHP开发中的应用包括:1.单一职责原则(SRP):每个类只负责一个功能。2.开闭原则(OCP):通过扩展而非修改实现变化。3.里氏替换原则(LSP):子类可替换基类而不影响程序正确性。4.接口隔离原则(ISP):使用细粒度接口避免依赖不使用的方法。5.依赖倒置原则(DIP):高低层次模块都依赖于抽象,通过依赖注入实现。

如何在系统重启后自动设置unixsocket的权限每次系统重启后,我们都需要执行以下命令来修改unixsocket的权限:sudo...

在PHPStorm中如何进行CLI模式的调试?在使用PHPStorm进行开发时,有时我们需要在命令行界面(CLI)模式下调试PHP�...

静态绑定(static::)在PHP中实现晚期静态绑定(LSB),允许在静态上下文中引用调用类而非定义类。1)解析过程在运行时进行,2)在继承关系中向上查找调用类,3)可能带来性能开销。

使用PHP的cURL库发送JSON数据在PHP开发中,经常需要与外部API进行交互,其中一种常见的方式是使用cURL库发送POST�...
