公司最近项目不忙,午间小憩之后,小二找到 C 哥攀谈了起来。
"C 哥,忙啥呢?" "也没忙啥,就是随便看看。"
"哦哦,我最近也不怎么忙。你上次给我讲的工厂模式,受益匪浅啊!" "哈哈,是嘛!其实你不知道,还有抽象工厂模式呢!"
"抽象工厂模式?愿闻其详。" "好,反正最近也不忙,就给你讲讲吧。"
"小二,你知道,奥迪 A4 与 A6,他们使用的轮胎与灯泡是不一样的。" "是,型号不一样,轮胎与灯泡肯定不一样。"
"假设现在需要制造 A4 与 A6 的轮胎和灯泡,你会怎么写代码?" "这个嘛,好写!"
小二熟练的打开电脑,挥斥方遒,迅速的写出了代码。
<?php
class Client{
//根据不同型号生产不同轮胎
public function produce_wheel($type){
switch ($type){
case 'A4':
$obj=new AudiA4Wheel();
break;
case 'A6':
$obj=new AudiA6Wheel();
break;
default:
throw new Exception('no instance found');
}
$obj->produce_wheel();
}
//根据不同型号生产不同灯泡
public function produce_light($type){
switch ($type){
case 'A4':
$obj=new AudiA4Light();
break;
case 'A6':
$obj=new AudiA6Light();
break;
default:
throw new Exception('no instance found');
}
$obj->produce_light();
}
}
$client=new Client();
$client->produce_wheel('A4');
$client->produce_light('A4');
"C 哥,大体就是这么个思路。您看看对吗?" "嗯,这代码确实也实现了功能,但是,有问题。"
"有问题?什么问题?" "你这代码存在着低内聚、高耦合的问题,不好维护啊。"
"怎么低内聚、高耦合了?"小二一脸茫然。
C 哥不慌不忙的解释道:
比如,现在我要增加奥迪的型号 A8,那你代码里的函数produce_wheel()
与produce_light()
是不是都要改?也就是这两个函数是相互依赖的,不可能用 A6 的轮子,而用 A8 的灯泡。相互依赖,是为高耦合。
produce_wheel()
与 produce_light()
函数,这两个函数都关心自己需要什么型号的产品,并且都负责把相应的产品生产出来。也就是,他有两个职责:关心型号、根据不同型号生产出对应的产品。但这两个职责是毫无关联的,没有半毛钱的关系。职责过多且分散,是为低内聚。
"C 哥这么一说,还真是这么回事。" "哈哈,低内聚高耦合的代码也能实现需求,但是这样的代码不好维护。"
"嗯嗯,C 哥,有啥好办法吗?" "当然有了,我们这里就用到了抽象工厂模式。"
"根据我多年的经验,出现 switch 语句的地方,往往意味着需要抽象、或者存在着放错责任的地方。" "宝贵的经验,记下了!"
"小二,其实这里,就是放错了责任。" "嗯,怎么说呢?"
"Client 端既关心如何创建对象,又关心如何用对象来制造轮子、灯泡。" "是,他的责任太多了。"
"其实,Client 端只负责使用对象制造相关产品就行了。他不用负责创造对象。创造对象,交给 Client 端来做,就是放错了责任。" "对,确实是这样。"
"还记得前几天给你讲的工厂模式吗?工厂模式也是为了解决这个问题。" "记得记得,工厂模式也是为了实现责任的分离。"
"工厂模式针对一种产品提供一个工厂类,而抽象工厂模式是针对一组相关或相互依赖的产品提供一个工厂类。" "那抽象工厂模式就是工厂模式的升级版本啦!"
"是的。在这里,Client 端负责向 Factory 发出请求,Factory 返回相关对象,Client 端再根据 Factory 返回的对象,制造相关的产品。" "也就是 Client 负责使用对象,Factory 负责创建对象!"
"是的,小二很聪明嘛!看看抽象工厂模式的类图吧!" "好的,C 哥。"
"小二啊,跟你讲了这么多,接下来就看你了!" "好的 C 哥,我马上画出类图、写出代码。"
小二仿照着 C 哥的类图,又画出了用抽象工厂解决上面问题的类图。
<?php
//灯泡产品接口
interface Light{
public function produce_light();
}
//奥迪 A4 灯泡产品
class AudiA4Light implements Light{
public function produce_light()
{
echo "AudiA4 Light produced!\n";
}
}
//奥迪 A6 灯泡产品
class AudiA6Light implements Light{
public function produce_light()
{
echo "AudiA6 Light produced!\n";
}
}
//轮子产品接口
interface Wheel{
public function produce_wheel();
}
//奥迪 A4 轮子
class AudiA4Wheel implements Wheel {
public function produce_wheel()
{
echo "AudiA4 Wheel produced!\n";
}
}
//奥迪 A6 轮子
class AudiA6Wheel implements Wheel {
public function produce_wheel()
{
echo "AudiA6 Wheel produced!\n";
}
}
//工厂接口
interface Factory{
public function CreateWheel();
public function CreateLight();
}
//奥迪 A4 工厂
class A4Factory implements Factory {
public function CreateWheel()
{
return new AudiA4Wheel();
}
public function CreateLight()
{
return new AudiA4Light();
}
}
//奥迪 A6 工厂
class A6Factory implements Factory {
public function CreateWheel()
{
return new AudiA6Wheel();
}
public function CreateLight()
{
return new AudiA6Light();
}
}
//客户端调用类
class Client{
//运行主函数
public static function main($type){
$reflection=new ReflectionClass($type.'Factory');
$factory=$reflection->newInstance();
self::run($factory);
}
//生产产品
public static function run(Factory $factory){
$wheel=$factory->CreateWheel();
$wheel->produce_wheel();
$light=$factory->CreateLight();
$light->produce_light();
}
}
Client::main('A6');
"嗯嗯,小二不错嘛。简单工厂、工厂方法、抽象工厂模式,你都掌握了。" "哈哈,感谢 C 哥的教导!"
"恭喜你在设计模式打怪升级的道路上,再次斩获新技能!"
听到这句话,小二心里美滋滋的,嘴角露出了得意的微笑......
转载声明:本文转载自「聊聊代码」,搜索「 talkpoem 」即可关注。
关注「聊聊代码」,让我们一起聊聊“左手代码右手诗”的事儿。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.