当前位置: 首页 > 编程日记 > 正文

设计模式系列·抽象工厂模式

前言

以小说的笔法写的设计模式系列文章,你绝对看得懂![首发于公众号:"聊聊代码"]

设计模式系列·王小二需求历险记(一)
设计模式系列·王小二需求历险记(二)
设计模式系列·封装、继承、多态
设计模式系列·初探设计模式之王小二的疑问
设计模式系列·Facade模式之MVC的烦恼
设计模式系列·Adapter 模式之如何优雅的使用别人的轮子
设计模式系列·类爆炸之Bridge模式
设计模式系列·工厂方法模式之 Code Review
设计模式系列·抽象工厂模式

------华丽的分割线:正文开始------

午后闲谈

公司最近项目不忙,午间小憩之后,小二找到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」即可关注。

关注「聊聊代码」,让我们一起聊聊“左手代码右手诗”的事儿。

相关文章:

14级团队学习成果汇报 -- 利用express+socket.io搭建简易版聊天室

周鹏&#xff0c;14级数理系&#xff0c;信息与计算科学大三学生。在LSGO软件技术团队负责前端部分&#xff0c;本图文是他的一个完整作品&#xff0c;代码可在Github上下载。

String复习笔记

注&#xff1a;可以在我的下载中下载完整word版 我的String学习体系 不可变 常见操作 补充&#xff1a;重载 在变成连接符String s "abc"24"haha";格式化输出 thinking in java 的例子 StringBuffer 简介 常见操作

面向对象模型的四种核心技术

1、分类类是具有相同属性结构和操作方法的对象的集合&#xff0c;属于同一类的对象具有相同的属性结构和操作方法。分类是把一组具有相同属性结构和操作方法的对象归纳或映射为一个公共类的过程。对象和类的关系是“实例”(instance-of)的关系。同一个类中的若干个对象&#xf…

Matlab与线性代数 -- 线性间隔向量

这段时间有同学给我后台留言&#xff0c;希望能够推送与Matlab相关的内容&#xff0c;本学期该微信号承担了数理系信息教研室线性代数课程内容推送和通知的任务&#xff0c;想来想去&#xff0c;就以此为契机&#xff0c;把Matlab和线性代数的内容结合起来吧&#xff0c;希望对…

盖茨基金会:如何使用Python拯救生命

每年全球都要花费数十亿美元来预防疾病&#xff0c;减少死亡&#xff0c;资助预防保健及治疗的各种研发项目&#xff0c;以及其他的健康方案。但资金毕竟是有限的&#xff0c;所以一些组织&#xff0c;比如全球卫生资金的主要捐助者比尔&梅林达盖茨基金会&#xff08;Billa…

正则表达式复习笔记

注&#xff1a;可以在我的下载中下载完整word版 复习体系 简介 正则表达式是:符合一定规则的表达式。 作用&#xff1a;用于专门操作字符串。 特点&#xff1a;用一些特定的符号来表示一些代码操作。这样就简化书写。 所以学习正则表达式&#xff0c;就是在学习一些特殊符号…

规划文章的“显示效果”,还是太多犹豫。

现在的一篇文章可能有“带图片”&#xff08;现称焦点&#xff09;&#xff0c;头条&#xff08;可能要重新命名标题&#xff09;&#xff0c;有几种显示效果的情况怎么办&#xff1f;把头条和焦点规划到一起来&#xff1f;想不出一个比较好的解决方案。初步准备“一对多”。先…

Matlab与线性代数 -- 方阵的行列式

这段时间有同学给我后台留言&#xff0c;希望能够推送与Matlab相关的内容&#xff0c;本学期该微信号承担了数理系信息教研室线性代数课程内容推送和通知的任务&#xff0c;想来想去&#xff0c;就以此为契机&#xff0c;把Matlab和线性代数的内容结合起来吧&#xff0c;希望对…

《深入浅出iPhone/iPad开发(第2版)》——在Xcode中建立你的界面

本节书摘来自异步社区《深入浅出iPhone/iPad开发&#xff08;第2版&#xff09;》一书中的在Xcode中建立你的界面&#xff0c;作者 【美】Dan Pilone , Tracey Pilone&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看 在Xcode中建立你的界面深入浅出iPhone/iPa…

Struts2+spring+jdbc 以xml配置形式整合

今天做作业&#xff0c;练习一下Struts2springjdbc 以xml配置形式整合 整合步骤&#xff1a; 工程结构图&#xff1a; 重要配置文件 web.xml <?xml version"1.0" encoding"UTF-8"?> <web-app version"2.5" xmlns"http://java.…

我和你不了的故事

我和你不了的故事——代腾飞 2006年12月11日 于成都你无言告别而消失得无影无踪我的世界只留下了你昔日的背影从此你我相隔在不远不近的时空里然而我却失去了你所有的联系你带走的是我们在一起的欢歌笑语为我留下的却是思念的苦楚和美妙而难忘的回忆不知此时的你是否偶尔能把…

前后端分离的探索(四)

文桥&#xff0c;13级机械电子工程系&#xff0c;大四学生。在LSGO软件技术团队负责前端部分&#xff0c;本图文是介绍目前流行的前后端分离技术的第四篇&#xff08;一共六篇&#xff09;&#xff0c;希望大家能够对这块有所了解。

《Adobe Fireworks CS5中文版经典教程》——导读

前言Adobe Fireworks CS5是一款专业级图像处理应用程序&#xff0c;融矢量和位图处理功能于一身。之所以采取独特的图像处理方法&#xff0c;是由于Fireworks旨在让用户能够创建和处理屏幕图形&#xff0c;以供Web或诸如移动应用程序和Adobe Flash等基于屏幕的工具使用。Firewo…

使用wsimport生成本地调用代码

使用wsimport生成本地调用的步骤 wsimport是jdk自带的,可以根据wsdl文档生成客户端调用代码的工具. wsimport.exe位于JAVA_HOME\bin目录下. 常用参数为: -d<目录> - 将生成.class文件。默认参数。 -s<目录> - 将生成.java文件。 -p<生成的新包名> -将生成的…

单片机练习-RC-5红外遥控器程序及简单制造DIY PC遥控器

本程序采用的芯片为SAA3010, 参考资料有:1. 常用红外遥控接收头引脚图解2. 红外遥控编码资料3. RC-5红外遥控程序 4. GIRDER中文教程与电脑遥控器制作资料 5. Girder网站 (一个需要钱买的遥控)6. 再度出击&#xff0c;20元打造经典PC遥控器&#xff01;7. SAA3010 DataSheet这次…

《iOS9开发快速入门》——导读

本节书摘来自异步社区《iOS9开发快速入门》一书中的目录&#xff0c;作者 刘丽霞 , 邱晓华&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看 目 录前 言 第1章 iOS 9开发概述 1.1 iOS 9新特性 1.2 构建开发环境—Xcode 7.0 1.3 编写第一个iOS 9应用 1.4 小…

C#语言与面向对象技术(4)

本图文主要掌握以下问题&#xff1a; 1. 为什么要引入属性的概念&#xff1f; 2. 属性的get与set方法是怎样定义的&#xff1f; 3. 什么是索引器&#xff1f; 4. 索引器是如何实现的&#xff1f;

使用wsdl2java命令生成webservice本地调用代码

使用wsdl2java命令生成webservice本地调用代码 如果没有设置环境变量&#xff0c;就要先进入cxf的bin目录 例子&#xff1a; wsdl2java -d . http://localhost:7890/hello?wsdl 它包含以下参数&#xff1a; &#xff0d;d参数&#xff0c;指定代码生成的目录。 &#xff0d…

js表单验证大全

js验证表单大全1. 长度限制<script>function test() {if(document.a.b.value.length>50){alert("不能超过50个字符&#xff01;");document.a.b.focus();return false;}}</script><form namea οnsubmit"return test()"><textarea…

《为iPad而设计:打造畅销App》——大胆创意

本节书摘来自异步社区《为iPad而设计&#xff1a;打造畅销App》一书中的大胆创意作者【英】Chris Stevens&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看 大胆创意为iPad而设计&#xff1a;打造畅销App其他的应用开发者都在做什么呢&#xff1f;或许应该在应…

Matlab与线性代数 -- 对数化间隔向量

这段时间有同学给我后台留言&#xff0c;希望能够推送与Matlab相关的内容&#xff0c;本学期该微信号承担了数理系信息教研室线性代数课程内容推送和通知的任务&#xff0c;想来想去&#xff0c;就以此为契机&#xff0c;把Matlab和线性代数的内容结合起来吧&#xff0c;希望对…

ContentProvider访问问题

问题解决一&#xff1a; 写了一个类&#xff0c;实现了ContentProvider&#xff0c;在清单文件中也注册了。 <provider android:name".provider.MyProvider" android:authorities"mytest" /> 但是访问的时候出现异常&#xff1a; j…

《C++面向对象高效编程(第2版)》——3.11 类名、成员函数名、参数类型和文档...

本节书摘来自异步社区出版社《C面向对象高效编程&#xff08;第2版&#xff09;》一书中的第3章&#xff0c;第3.11节&#xff0c;作者&#xff1a; 【美】Kayshav Dattatri&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看。 3.11 类名、成员函数名、参数类型…

一个GDIPlus的Bug -- OutofMemory异常

今天发现 framework2.0中的一个GDIPlus的Bug: 在Form的OnPaint事件里面写如下代码&#xff1a; private void Form1_Paint(object sender, PaintEventArgs e) { Pen p new Pen(Color.Red); p.Width 1; p.DashStyle DashStyl…

前后端分离的探索(五)

文桥&#xff0c;13级机械工程系&#xff0c;机械电子工程专业&#xff0c;大四学生。在LSGO软件技术团队负责前端部分&#xff0c;本图文是介绍目前流行的前后端分离技术的第五篇&#xff08;一共六篇&#xff09;&#xff0c;希望大家能够对这块有所了解。

从一道面试题分析Thread.interrupt方法

阿里面试题&#xff1a; public class TestThread {public static void main(String[] args) {Thread t1 new Thread() {Overridepublic void run() {try {int i 0;while (i < 100000000) {// nothing}System.out.println("A1");} catch (Exception e) {System.…

对联广告,带关闭,可以移动

在网页中加入以下代码 两个图的&#xff0c;一个是关闭用到的&#xff0c;一个是广告图 <script languageJavaScript src"js/scroll.js"></script> js代码如下&#xff1a; suspendcode"<DIV idlovexin1 styleZ-INDEX: 10; LEFT: 6px; POSITION…

u一点·料:阿里巴巴1688ued体验设计践行之路. 导读

U一点料 阿里巴巴1688UED体验设计践行之路 阿里巴巴1688用户体验部著 前言 既赶路&#xff0c;也感受路 文 / 汪方进 用户体验设计师作为一个职能岗位&#xff0c;在国内互联网公司中存在已有十几年的时间了&#xff0c;早期的互联网公司设计师大都是无所不能的多面手&#xff…

Matlab与线性代数 -- 显示格式的设置

打磨一项技能最需要的就是耐心&#xff0c;我们知道做一件事情不会一蹴而就&#xff0c;需要长时间的积累。关于Matlab的打磨会持续很长的时间&#xff0c;每天学习一个知识点&#xff0c;一年下来就不得了。要有耐心&#xff0c;要有耐心&#xff0c;跟着小编每天花5分钟的时间…

java初始化顺序

java初始化顺序