白话设计模式——Abstract Factory

Abstract Factory,把英文直接翻译过来的话就是“抽象工厂”,既然是工厂,那就肯定是生产产品的地方。不过,它不是生产同一类的产品,而是生产同一系列的产品。举个例子,广州本田现在生产3种汽车,OdysseyAccordFit,而广本的工厂里面并不是拥有3条不同的生产线以生产不同的汽车。这就非常相似于我们正在讨论的抽象工厂模式,广本在生产不同的汽车时,需要在各个生产环节进行修改,换机器自然是不合适的,因为这3种汽车每天都要生产,分时段而已。如果某一个环节的更换工作出了问题都会有大麻烦,比如Fit的车顶肯定装不到Odyssey上。我们在软件设计的时候也是这样,如果需要某一系列配套的类来进行工作,当这个系列中有一个类用错了,后果都是不好的。再回到广本的例子上,当广本准备生产另外一种汽车时,只需要拥有相应的配套模具(还有其他的一些配件和一些数控设备的控制程序)就可以了,没有必要搞一大堆的生产线。

再来一个生活中的例子,西服+西裤+皮鞋+白衬衫+领带+头发梳得顺顺的,出入高级会所或者重要场合的时候,男人一般都这样穿;休闲装+运动鞋+随意的发型,生活中就这样穿,舒服;睡衣+拖鞋+鸡窝头,早上就这样。每一种都是合适的造型,如果你搞成如下这样的造型就不合适了,西服+西裤+回力鞋+超级大背包+鸡窝头,广州火车站很多同志都是这样打扮的。

抽象工厂模式是一种创建型的模式。上面的比喻说明了抽象工厂就是生产同一个系列产品的东西,因为这一系列的产品是关联的,如果混用就可能出问题,所以就统一的在抽象工厂中进行创建。当要增加一个新的产品系列时,就多写一个工厂子类并添加相应的产品子类就可以了。

我们来看一个类图。

 af.jpg


   图中,我们可以看到,客户需要得到某系列的产品的时候,直接用相应的工厂子类来创建产品就可以了。比如,当需要生产
Fit时,就用FitFactory,等到换班之后,要生产Odyssey了,直接使用OdysseyFactory替换FitFactory就行了,至于怎么替换就随便了,GoF也给了我们一些建议,我将在后面总结创建型模式的时候讲。

把上面的类图转换成代码,应该是这个样子。

关于车门的类:

None.gif    public abstract class AbstractDoor
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
ExpandedBlockEnd.gif    }

None.gif
None.gif    
public class FitDoor : AbstractDoor
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
ExpandedBlockEnd.gif    }

None.gif
None.gif    
public class OdysseyDoor : AbstractDoor
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
ExpandedBlockEnd.gif    }


关于底盘的类:

None.gif    public abstract class AbstractChassis
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
ExpandedBlockEnd.gif    }

None.gif
None.gif    
public class FitChassis : AbstractChassis
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
ExpandedBlockEnd.gif    }

None.gif
None.gif    
public class OdysseyChassis : AbstractChassis
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
ExpandedBlockEnd.gif    }


关于工厂的类:

None.gif    public abstract class HondaFactory
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
InBlock.gif        
public abstract AbstractDoor CreateDoor();
InBlock.gif        
public abstract AbstractChassis CreateChassis();
ExpandedBlockEnd.gif    }

None.gif
None.gif    
public class FitFactory
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
InBlock.gif        
public AbstractDoor CreateDoor()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return new FitDoor();
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public AbstractChassis CreateChassis()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return new FitChassis();
ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }

None.gif
None.gif    
public class OdysseyFactory
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
InBlock.gif        
public AbstractDoor CreateDoor()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return new OdysseyDoor();
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public AbstractChassis CreateChassis()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return new OdysseyChassis();
ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }

 
客户的调用:

None.gif    public class Client
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
InBlock.gif        
private AbstractDoor _door;
InBlock.gif        
private AbstractChassis _chassis;
InBlock.gif        
private HondaFactory _factory;
InBlock.gif
InBlock.gif        
public void GetACar(string seriesName)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
this.PrepareFactory(seriesName);
InBlock.gif            
this._door = this._factory.CreateDoor();
InBlock.gif            
this._chassis = this._factory.CreateChassis();
InBlock.gif
InBlock.gif            
// TODO: Make a car!
ExpandedSubBlockEnd.gif
        }

InBlock.gif
InBlock.gif        
private void PrepareFactory(string seriesName)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
switch(seriesName)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
case "Fit":
InBlock.gif                    
this._factory = new FitFactory();
InBlock.gif                    
break;
InBlock.gif                
case "Odyssey":
InBlock.gif                    
this._factory = new OdysseyFactory();
InBlock.gif                    
break;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }




   抽象工厂的优点很明显了,就是在需要用到一系列相关类的地方,它可以使我们不出错的创建出一系列的类实例,而我们在需要添加新的产品系列的时候,完全不需要考虑其他系列的问题,仅需要将相关的抽象类(工厂已经产品)具体化就可以了。缺点也在这个地方,当工厂需要生产多一种产品(不是系列)的时候,改动将波及所有类,比如,广本打算在每一辆汽车上装一个翅膀,那就需要在工厂中添加一个冲压机(以及各种车型的翅膀模具),还要在焊接科里添加这么一道工序,涂装科以及总装科里面也一样要进行相应的调整。

 

 

工厂子类不一定需要实现父类的所有方法,但要使子类有用的话,我们必须使它的所有方法宣布具体化。这里,就引出几种做法:1、工厂父类可以就是一个接口,以确保其子类一定是具体的;2、我们可以继承抽象的父类,但不完全具体化,这样可以继续细分工厂子类;3、抽象的父类中含有具体的方法,这些方法也可以不加virtual修饰符。最后的这种方法可能是比较灵活一点的。

抽象工厂主要是用在需要一系列相关联的类协同工作的地方,而且这些系列的数量可能会变多,每一个系列完成的工作都不一样,但是调用接口却是一样的。另外,抽象工厂不适合这样一种情况,即每个系列内部的元素数量不能够确定,也就是说,当初设计的时候,系列中有3个配件,后面又涨成5个,之后又涨到7个,这样的话,要改动的地方将多到让人受不了。


回到目录
上一篇:引子
下一篇:Builder

转载于:https://www.cnblogs.com/Reeezak/archive/2005/10/23/260493.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/467376.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工程师实战:单片机裸机程序框架是怎样炼成的?

前言 前不久,我有位做测试的朋友转去做开发的工作,面试遇到了一个问题,他没明白,打电话问了我。题目大概就是:在单片机裸机开发时,单片机要处理多个任务,此时你的程序框架是怎样的呢&#xff1f…

c 语言指针教学视频,[C语言] 猎豹网校 C和指针视频教程

资源介绍21days_Cpp_二进制和十六进制.mp4xa0xa080x86_内联汇编.mp4xa0xa0ABG2C_for_循环.mp4xa0xa0ABG2C_关系运算符.mp4xa0xa0ABG2C_字符串.mp4xa0xa0ABG2C_循环.mp4xa0xa0ABG2C_数学运算.mp4xa0xa0ABG2C_更高级的运算符.mp4xa0xa0ABG2C_测试多个值.mp4xa0xa0ABG2C_终止循环.…

图解http

今天是周五,按照正常的情况,今天下班后将会经历一周中最愉快的时光,愉快的时间总是会有那么一些短暂,所以我就送给大家一个资料 「图解http」这是一个微信好友发给我的,他一直给我发送了很多很多消息,比如什…

为什么执行自己的程序要在前面加./

前言在Linux中,我们执行内置命令时,直接输入命令名称即可,如:$ mv a b #将a重命名为b而在执行自己写好的程序时,却要带上./,例如:$ hello hello: command not found $ ./hello hello world这是为…

C语言怎么计算数据类型范围?

之前在网上看到的一个讨论,是谁决定了数据类型的范围?比如说,怎么确定 char 就是 -128~127 ,而不是 -127~128 呢?说下规定signed 的取值范围是 -(2N-1) to 2N-1 - 1unsigned 的取值范围是 0 to (2N-1) (2N-1 - 1)只要…

双十一为何规则复杂,套路多多

为啥不直接打5折?为了让你把“穷人”俩字写到自己脸上啊。 双十一快到了,今年我又一次有了不太想参加的感觉。作为一个阅读理解不太灵光的人,去年的活动我就整得不太明白——优惠券都是十块十块的,也不知道该咋用;还有预付款、整点秒杀之类的…

团建是什么鬼?

2012年我入职TCL,在TCL我体会到了团队建设的文化,也正是经历了那段职场,我明白了很多「可意味不可言传」。那时候我们经常五十成群出去吃饭、喝酒、唱歌;上学那会我很不喜欢团队活动,特别是室内的活动,总感…

Alpha 答辩总结

【Alpha展示评审表格】 小组序号小组名称格式(20%)内容(20%)PPT(20%)演讲(20%)答辩(20%)总分1天机组1515151516762PMS1617171616824“像我这么能打的还有五个…

一粒沙子变成芯片的全过程

推荐阅读:专辑|Linux文章汇总专辑|程序人生专辑|C语言嵌入式Linux微信扫描二维码,关注我的公众号

要学会拒绝

Img「聊天截图」这是今晚上跟一个朋友聊天的截图,之后、突然想到这个话题,今年因为疫情,很多人抱怨工作不好找,我这个朋友,也是在疫情之下,可能是干得不开心,也可能还是干得不开心,可…

linux设备模型之kset/kobj/ktype分析

1. 概述今天来聊一下Linux设备模型的基石:kset/kobject/ktype。sysfs文件系统提供了一种用户与内核数据结构进行交互的方式,可以通过mount -t sysfs sysfs /sys来进行挂载;Linux设备模型中,设备、驱动、总线组织成拓扑结构&#x…

VLAN 路由实验图解

VLAN 路由实验图解(交换机为cisco1900系列)注:PC1:192.168.1.2 255.255.255.0PC2:192.168.2.2 255.255.255.0PC3:192.168.1.3 255.255.255.0PC4:192.168.2.3 255.255.255.0Fa0/0.1:192.168.1.1 255.255.255…

第 120 场双周赛 解题报告 | 珂学家 | 前后缀拆解 启发式合并

前言 忘名可以再记,回忆永不再来 整体评价 好像有一段时间没写周赛题解了,_. 感觉今天手感特别好,下午的几场比赛,包括传智杯都能打出超神战绩。 T3这题属于前后缀拆解,然后单调栈上二分(可以引入哨兵机制)&#xf…

音频系统,Alsa 里面的buff 是怎么计算的?

相关文章(干货)Ai音箱和Linux音频驱动小谈Linux ALSA 图解我在MTK平台下调试音频ALSA我们知道声音是模拟信号,模拟信号转成数字信号就一定有大小,既然有大小,那我们就需要开辟内存来保存这些数据。---- 我们知道,视频流的一帧就是…

用一句话证明你是程序员,你会怎么说

这个文章没有正文突然想到的一个话题,感觉很有意思如果用一句话透露出你是一个程序员你会怎么表露自己了?留言偷偷告诉我?

空间换时间,查表法的经典例子

前言 上一篇分享了:C语言精华知识:表驱动法编程实践这一篇再分享一个查表法经典的例子。我们怎么衡量一个函数/代码块/算法的优劣呢?这需要从多个角度看待。本篇笔记我们先不考虑代码可读性、规范性、可移植性那些角度。在我们嵌入式中&#…

Linux内核系统架构介绍

28年前(1991年8月26日)Linus公开Linux的代码,开启了一个伟大的时代。这篇文章从进程调度,内存管理,设备驱动,文件系统,网络等方面讲解Linux内核系统架构。Linux的系统架构是一个经典的设计,它优秀的分层和模…

这道笔试题竟然运行不出错

#读者提供的面试题下面这张截图是一个读者在面试的时候遇到的题目,是哪个公司的我就不说出来了,我在微信朋友圈发了这个题目后,有几个好友给我留言说自己也写了这道题。题目:下面这段代码有什么问题?#后续然后我就用这…

android加号底部导航栏,EasyNavigation Android 底部导航栏████几行代码实现 Tab 导航(随意定制加号,带红点消息提示) @codeKK Android开源站...

几行代码轻松实现底部导航栏(Tab 文字图片高度随意更改);中间可添加加号按钮,也可添加文字;(足够的属性满足你需要实现的加号样式)如果还不能满足、中间可添加自定义 View;Tab 中随意添加小红点提示、数字消息提示;点击…

在工厂的这几天

上周在工厂呆了6天支持我们产品量产,说下自己在工厂看到的一些事情,可能对大家对嵌入式行业有一定的认识,这样大家在选择方向会有些借鉴作用。产品由研发到生产是一个过程,只有经受过量产考验的产品,才能说这个产品真正…