研磨设计模式之工厂方法模式_第1页
研磨设计模式之工厂方法模式_第2页
研磨设计模式之工厂方法模式_第3页
研磨设计模式之工厂方法模式_第4页
研磨设计模式之工厂方法模式_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

研磨设计模式之工厂方法模式-1

做Java一晃就十年了,最近手痒痒,也决定跟随一下潮流,整个博客,写点东西,就算对自己的知识进行一个梳理和总结,也跟朋友们交流交流,希望能坚持下去。

先写写设计模式方面的内容吧,就是GoF的23个模式,先从大家最熟悉的工厂方法模式开始,这个最简单,明白的人多,看看是否能写出点跟别人不一样的东西,欢迎大家来热烈讨论,提出建议或意见,并进行批评指正,一概虚心接受,在此先谢过了!

另外,大家也可以说说最想看到哪个模式,那我就先写它,呵呵,大家感兴趣,我才会有动力写下去!好了,言归正传,NowGo!工厂方法模式(FactoryMethod)1

场景问题1.1

导出数据的应用框架

考虑这样一个实际应用:实现一个导出数据的应用框架,来让客户选择数据的导出方式,并真正执行数据导出。

在一些实际的企业应用中,一个公司的系统往往分散在很多个不同的地方运行,比如各个分公司或者是门市点,公司没有建立全公司专网的实力,但是又不愿意让业务数据实时的在广域网上传递,一个是考虑数据安全的问题,一个是运行速度的问题。

这种系统通常会有一个折中的方案,那就是各个分公司内运行系统的时候是独立的,是在自己分公司的局域网内运行。然后在每天业务结束的时候,各个分公司会导出自己的业务数据,然后把业务数据打包通过网络传送给总公司,或是专人把数据送到总公司,然后由总公司进行数据导入和核算。

通常这种系统,在导出数据上,会有一些约定的方式,比如导出成:文本格式、数据库备份形式、Excel格式、Xml格式等等。

现在就来考虑实现这样一个应用框架。在继续之前,先来了解一些关于框架的知识。1.2

框架的基础知识(1):框架是什么

简单点说:框架就是能完成一定功能的半成品软件。

就其本质而言,框架是一个软件,而且是一个半成品的软件。所谓半成品,就是还不能完全实现用户需要的功能,框架只是实现用户需要的功能的一部分,还需要进一步加工,才能成为一个满足用户需要的、完整的软件。因此框架级的软件,它的主要客户是开发人员,而不是最终用户。

有些朋友会想,既然框架只是个半成品,那何必要去学习和使用框架呢?学习成本也不算小,那就是因为框架能完成一定的功能,也就是这“框架已经完成的一定的功能”在吸引着开发人员,让大家投入去学习和使用框架。(2):框架能干什么能完成一定功能,加快应用开发进度

由于框架完成了一定的功能,而且通常是一些基础的、有难度的、通用的功能,这就避免我们在应用开发的时候完全从头开始,而是在框架已有的功能之上继续开发,也就是说会复用框架的功能,从而加快应用的开发进度。给我们一个精良的程序架构

框架定义了应用的整体结构,包括类和对象的分割,各部分的主要责任,类和对象怎么协作,以及控制流程等等。现在Java界大多数流行的框架,大都出自大师手笔,设计都很精良。基于这样的框架来开发,一般会遵循框架已经规划好的结构来进行开发,从而让我们开发的应用程序的结构也相对变得精良了。(3):对框架的理解基于框架来开发,事情还是那些事情,只是看谁做的问题

对于应用程序和框架的关系,可以用一个图来简单描述一下,如图1所示:

图1

应用程序和框架的简单关系示意图

如果没有框架,那么客户要求的所有功能都由开发人员自己来开发,没问题,同样可以实现用户要求的功能,只是开发人员的工作多点。

如果有了框架,框架本身完成了一定的功能,那么框架已有的功能,开发人员就可以不做了,开发人员只需要完成框架没有的功能,最后同样是完成客户要求的所有功能,但是开发人员的工作就减少了。

也就是说,基于框架来开发,软件要完成的功能并没有变化,还是客户要求的所有功能,也就是“事情还是那些事情”的意思。但是有了框架过后,框架完成了一部分功能,然后开发人员再完成一部分功能,最后由框架和开发人员合起来完成了整个软件的功能,也就是看这些功能“由谁做”的问题。

基于框架开发,可以不去做框架所做的事情,但是应该明白框架在干什么,以及框架是如何实现相应功能的

事实上,在实际开发中,应用程序和框架的关系,通常都不会如上面讲述的那样,分得那么清楚,更为普遍的是相互交互的,也就是应用程序做一部分工作,然后框架做一部分工作,然后应用程序再做一部分工作,然后框架再做一部分工作,如此交错,最后由应用程序和框架组合起来完成用户的功能要求。

也用个图来说明,如图2所示:

图2

应用程序和框架的关系示意图

如果把这个由应用程序和框架组合在一起构成的矩形,当作最后完成的软件。试想一下,如果你不懂框架在干什么的话,相当于框架对你来讲是个黑盒,也就是相当于在上面图2中,去掉框架的两块,会发现什么?没错,剩下的应用程序是支离破碎的,是相互分隔开来的。

这会导致一个非常致命的问题,整个应用是如何运转起来的,你是不清楚的,也就是说对你而言,项目已经失控了,从项目管理的角度来讲,这是很危险的。

因此,在基于框架开发的时候,虽然我们可以不去做框架所做的事情,但是应该搞明白框架在干什么,如果条件许可的话,还应该搞清楚框架是如何实现相应功能的,至少应该把大致的实现思路和实现步骤搞清楚,这样我们才能整体的掌控整个项目,才能尽量减少出现项目失控的情况。料(4):框邀架和设计模傍式的关系假宪

设计浸模式比框架渴更抽象忍厦

框架已随经是实现出史来的软件了厚,虽然只是葛个半成品的灾软件,但毕掏竟是已经实禁现出来的了造。而设计模辉式的重心还瘦在于解决问借题的方案上稀,也就是还塘停留在思想币的层面。因裙此设计模式训比框架更为获抽象。雾展抬届找设计模式是傻比框架更小销的体系结构说元素运糕

如上所鹊述,框架是秀已经实现出泄来的软件,少并实现了一余系列的功能蜂,因此一个境框架,通常奏会包含多个顿设计模式的展应用。库漂

框架逮比设计模式两更加特例化腊比

框架是饰完成一定功式能的半成品括软件,也就趣是说,框架信的目的很明来确,就是要诱解决某一个闪领域的某些峰问题,那是音很具体的功舅能,不同的涝领域实现出顿来的框架是凑不一样的。置促而设计模井式还停留在迈思想的层面运,在不同的未领域都可以艺应用,只要肺相应的问题气适合用某个拒设计模式来愤解决。因此战框架总是针聚对特定领域坝的,而设计伟模式更加注涌重从思想上暮,从方法上泳来解决问题丢,更加通用逼化。盯1.3

翻有何问题翻磁

分析上博面要实现的腹应用框架,糊不管用户选陪择什么样的课导出格式,为最后导出的勾都是一个文变件,而且系阁统并不知道追究竟要导出许成为什么样柴的文件,因客此应该有一犁个统一的接碎口,来描述袜系统最后生构成的对象,吐并操作输出踢的文件。盼扮

先把导设出的文件对阵象的接口定景义出来,示艘例代码如下救:

荐/**靠

*导出楚的文件对象摸的接口痒

*/焰publi故cint得erfac娃eExp商ortFi恒leApi句{代

/锡**校

荷*导出内出容成为文件既

斩*@pa画ramd吊ata示醉意:需要保盼存的数据赴

低*@re属turn关是否导出成厚功捏

扇*/咏

p猾ublic级bool要eane搁xport鸽(Stri炊ngda鸭ta);锡}税在

对于裁实现导出数近据的业务功缝能对象,它磁应该根据需们要来创建相粪应的Exp仓ortFi变leApi羡的实现对象岸,因为特定复的Expo棵rtFil冶eApi的凯实现是与具慎体的业务相僵关的。但是思对于实现导译出数据的业屈务功能对象妖而言,它并粪不知道应该快创建哪一个友Expor把tFile签Api的实岩现对象,也铲不知道如何拐创建。富喷哲也就是说:够对于实现导且出数据的业滑务功能对象溜,它需要创炒建Expo虫rtFil在eApi的陆具体实例对菠象,但是它胡只知道Ex喊portF趁ileAp妄i接口,而抛不知道其具由体的实现。乳那该怎么办餐呢?网研磨设计模阳式之工厂奋方法模式-什2伶

2

解弊决方案蹲2.1

阳工厂方法模开式来解决受秋

用来救解决上述问亮题的一个合琴理的解决方规案就是工厂熟方法模式。免那么什么是键工厂方法模犹式呢?挤(1)工厂摩方法模式定拒义李补

定义险一个用于创浓建对象的接俭口,让子类问决定实例化海哪一个类,与Facto邻ryMe吗thod使毅一个类的实贵例化延迟到网其子类。耗(2)应用户工厂方法模饮式来解决的接思路笋朴

仔细布分析上面的锋问题,事实沟上在实现导喂出数据的业串务功能对象尚里面,根本廉就不知道究瓦竟要使用哪娘一种导出文呆件的格式,乒因此这个对备象本就不应御该和具体的释导出文件的味对象耦合在狮一起,它只悉需要面向导茎出的文件对头象的接口就匀好了。循热

但是篮这样一来,纠又有新的问弃题产生了:籍接口是不能唇直接使用的盛,需要使用汗具体的接口顶实现对象的例实例。马称

这不寸是自相矛盾麻吗?要求面蛇向接口,不牢让和具体的驼实现耦合,亭但是又需要供创建接口的供具体实现对勾象的实例。简怎么解决这流个矛盾呢?肝靠

工厂服方法模式的绣解决思路很杠有意思,那悼就是不解决欣,采取无为烦而治的方式啦:不是需要苏接口对象吗厌,那就定义锄一个方法来哀创建;可是莫事实上它自束己是不知道堪如何创建这彩个接口对象役的,没有关叫系,那就定绘义成抽象方源法就好了,限自己实现不虎了,那就让违子类来实现俘,这样这个样对象本身就伯可以只是面汁向接口编程激,而无需关剩心到底如何弃创建接口对醉象了。鱼2.2

四模式结构和洁说明问墙

工厂贤方法模式的棒结构如图3蛇所示:羊坐拖杠纳图3

绣工厂方法模网式结构示意绣图肯Produ辛ct络:鹊胜

定义寇工厂方法所多创建的对象炼的接口,也滑就是实际需仁要使用的对扬象的接口。编Concr简etePr恰oduct锁:胞抵

具体阶的Prod唐uct接口骗的实现对象鸽。沸Creat注or:吊脾

创建京器,声明工撒厂方法,工仿厂方法通常胡会返回一个逃Produ斥ct类型的击实例对象,叨而且多是抽捆象方法。也喘可以在Cr购eator蚕里面提供工大厂方法的默梨认实现,让线工厂方法返鹿回一个缺省腔的Prod趟uct类型调的实例对象引。衬Concr经eteCr萄eator追:企善

具体虽的创建器对惭象,覆盖实医现Crea锁tor定义年的工厂方法料,返回具体朴的Prod想uct实例抖。授2.3

回工厂方法模杏式示例代码淡(1)先看丧看Prod犁uct的定拥义,示例代朋码如下:布/**南

*工厂词方法所创建定的对象的接最口滴

*/泪pu名blic虹inter宫face槽Produ稍ct{立

/现/可以定义娇Produ段ct的属性萍和方法际}务(2)再看染看具体的P何roduc撇t的实现对顾象,示例代什码如下:

盲/**滑

*具体像的Prod欺uct对象乐

*/声publi谜ccla嫌ssCo胸ncret必eProd礼ucti丹mplem考ents燃Produ左ct{蜘

/虏/实现Pr嗓oduct夏要求的方法匀}引(3)接下域来看看创建奖器的定义,雄示例代码如筹下:

用/**廉

*创建侄器,声明工美厂方法您

*/相publi企cabs嫁tract嫌clas血sCre怎ato僻r{溜

/典**戚

歼*创建P蹦roduc桃t的工厂方陕法常

像*@re直turn现Produ奔ct对象截

裤*/盟

p进rotec匀teda狗bstra欢ctPr借oduct立fact问oryMe视thod(起);蹲

/单**址

牌*示意方获法,实现某厌些功能的方边法漂

劣*/离

p党ublic疲void其some上Opera肠tion(浙){锋

//通谊常在这些方准法实现中,骑需要调用工康厂方法来获莲取Prod海uct对象菠

Pro击duct摩produ快ct=铺fa澡ctory左Metho饱d();孩

}问}漏(4)再看两看具体的创探建器实现对住象,示例代绒码如下:

籍/**绸

*具体素的创建器实扫现对象促

*/赞publi俊ccla穿ssCo仗ncret泰eCrea资tore论xtend款sCre混ator丝{妨

p熊rotec凑tedP励roduc挤tfac现toryM税ethod退(){校

//重摸定义工厂方泡法,返回一湾个具体的P胖roduc着t对象傅

ret弯urnn鸭ewCo栋ncret葬eProd驴uct()僵;豆

}旁}穗2.4

舞使用工厂方展法模式来实文现示例脂步

要使俩用工厂方法汽模式来实现朽示例,先来汇按照工厂方循法模式的结腔构,对应出递哪些是被创愈建的Pro拿duct,萝哪些是Cr来eator孕。分析要求丈实现的功能软,导出的文星件对象接口技Expor棚tFile撒Api就相薪当于是Pr河oduct申,而用来实硬现导出数据痰的业务功能杠对象就相当票于Crea便tor。把供Produ龟ct和Cr悉eator糖分开过后,窗就可以分别竖来实现它们斥了。身描

使用悬工厂模式来温实现示例的汗程序结构如铁图4所示:星再拉脆舌院些

图4殖

使用工浙厂模式来实枝现示例的程渐序结构示意蔽图祖

下面一起禾来看看代码假实现。待(1)导出庄的文件对象覆接口Exp箱ortFi怀leApi驾的实现没有层变化,这里葵就不去赘述走了利(2)接下屡来看看接口辉Expor殃tFile晴Api的实于现,为了示剩例简单,只影实现导出文聋本文件格式牲和数据库备办份文件两种朽。先看看导格出文本文件膝格式的实现简,示例代码访如下:

福/腹**痛

*导出全成文本文件墓格式的对象激

*/傍publi斗ccla带ssEx玩portT足xtFil鞭eimp财lemen诚tsEx玩portF张ileAp封i{绢

p贿ublic掌bool腿eane唱xport请(Stri钉ngda装ta){威

//简叨单示意一下纹,这里需要岗操作文件类

Sys邪tem.央out装.prin垄tln("帽导出数据"叶+data爆+"到文本歪文件");姥

ret让urnt底rue;英

}薪}穷再看看导出疗成数据库备刊份文件形式马的对象的实腐现,示例代睁码如下:

倾打/**桶

*导出祖成数据库备上份文件形式厚的对象伯

*/虎publi剥ccla逝ssEx缸portD帐Bimp民lemen蠢tsEx瘦portF埋ileAp骆i{徒

p毅ublic拴bool摧eane兵xport瞎(Stri摄ngda放ta){哨

//简脸单示意一下暮,这里需要球操作数据库劈和文件驻

Sys琴tem.畅out甲.prin嫂tln("池导出数据"野+data卵+"到数据来库备份文件贤");笨

ret雾urnt胆rue;曾

}烟}闹(3)Cr容eator盾这边的实现盒,首先看看里Expor窜tOper伶ate的实者现,示例代浩码如下:

板/**接

*实现跃导出数据的反业务功能对摇象党

*/态publi女cabs逝tract命clas便sExp倦ortOp以erate平{妙

/渴**睛

拳*导出文苹件仇

龟*@pa番ramd股ata需椅要保存的数雕据哲

炕*@re腔turn谋是否成功导失出文件缠

倡*/资

p被ublic新bool护eane睛xport耻(Stri友ngda轨ta){珠

//使如用工厂方法虚

Exp观ortFi晒leApi搬api淡=fac棒toryM爽ethod虎();袜

re止turn增api.e碑xport摸(data谢);紧

}吩

/谣**穗

珍*工厂方哄法,创建导跳出的文件对分象的接口对浸象苏

雕*@re玻turn田导出的文件箭对象的接口越对象列

敬*/未

p遭rotec见teda她bstra报ctEx满portF刺ileAp作ifac埋toryM竖ethod番();汪}湾(4)加入旺了两个Cr岂eator苏实现,先看邀看创建导出何成文本文件苗格式的对象克,示例代码臭如下:

仿/**喇

*具体去的创建器实芳现对象,实甚现创建导出愧成文本文件胸格式的对象鞋

*/秧publi盘ccl主assE动xport准TxtFi丘leOpe隆rate奋exten却dsEx昨portO庭perat糟e{艺

p撒rotec秀tedE法xport她FileA统pifa耳ctory猜Metho布d(){回

沿

//创蝴建导出成文勺本文件格式药的对象驼

ret进urnn饿ewEx扩portT列xtFil猾e();羡

}吃}钳再看看创建汁导出成数据轿库备份文件娘形式的对象诱,示例代码倍如下:

阿/**申

*具体逗的创建器实毯现对象,实桂现创建导出慕成数据库备妻份文件形式蹲的对象精

*/锹publi瑞ccla稀ssEx禽portD吵B迎Opera盾teex驼tends坏Expo草rtOpe迅rate{贴

p狠rotec樱tedE腐xport迅FileA堡pifa亭ctory胖Metho活d(){释

//创呆建导出成数交据库备份文等件形式的对触象帮

ret陶urnn矩ewEx鼓portD栽B();侦

}布}崇(5)客户古端直接创建泼需要使用的论Creat魂or对象,盯然后调用相尚应的功能方惹法,示例代窜码如下:

宋饿publi狐ccla漫ssCl踩ient绿{界

p最ublic秩stat福icvo桂idma处in(St肤ring[肤]arg缎s){北

//创烛建需要使用您的Crea炸tor对象成

Exp变ortOp啦erate描oper摸ate=糊new免Expor斧tDBOp仅erate较();贯

//调钥用输出数据移的功能方法宰

ope宪rate.秃expor蓄t("测试窑数据");主

}盆}遭运行结果如研下:

糊导出数据测枕试数据到数柴据库备份文犁件朋涝

你燃还可以修改血客户端ne户w的对象,叙切换成其它常的实现对象伏,试试看会拖发生什么。算看来应用工瓶厂方法模式棕是很简单的参,对吧。挡研磨设计模关式之工厂莲方法模式-院3倚3

模式凑讲解涂3.1

扮认识工厂方丑法模式时(1)模式豆的功能欺袭

工厂炕方法的主要丛功能是让父构类在不知道懂具体实现的山情况下,完狂成自身的功掘能调用,而熟具体的实现场延迟到子类幕来实现。耳费

这样监在设计的时腹候,不用去哀考虑具体的芽实现,需要梢某个对象,宅把它通过工捞厂方法返回停就好了,在驴使用这些对弯象实现功能误的时候还是低通过接口来傍操作,这非线常类似于I退oC/DI建的思想,这岁个在后面给撑大家稍详细炒点介绍一下既。港(2)实现坊成抽象类亡伶

工厂摇方法的实现腥中,通常父赢类会是一个孟抽象类,里志面包含创建奉所需对象的闻抽象方法,商这些抽象方敬法就是工厂计方法。笼播

这里范要注意一个撕问题,子类积在实现这些出抽象方法的茫时候,通常赚并不是真的缓由子类来实居现具体的功冻能,而是在毫子类的方法并里面做选择艇,选择具体窃的产品实现届对象。半候

父类舟里面,通常主会有使用这须些产品对象婆来实现一定蹲的功能的方及法,而且这焰些方法所实灭现的功能通灰常都是公共绍的功能,不滩管子类选择辰了何种具体灭的产品实现丢,这些方法商的功能总是创能正确执行磨。测(3)实现歇成具体的类栏白

当然爱也可以把父泻类实现成为己一个具体的路类,这种情灾况下,通常港是在父类中幼提供获取所妇需对象的默裂认实现方法册,这样就算参没有具体的者子类,也能革够运行。屯乏

通常验这种情况还舅是需要具体歪的子类来决扎定具体要如燃何创建父类雕所需要的对肥象。也把这酒种情况称为路工厂方法为大子类提供了瞧挂钩,通过休工厂方法,爽可以让子类筐对象来覆盖陵父类的实现旦,从而提供丽更好的灵活翻性。音(4)工厂舅方法的参数绩和返回时献

工厂亚方法的实现营中,可能需拦要参数,以获便决定到底租选用哪一种矮具体的实现澡。也就是说锅通过在抽象展方法里面传采递参数,在字子类实现的熟时候根据参桂数进行选择潮,看看究竟驾应该创建哪德一个具体的拴实现对象。呆锻

一般龄工厂方法返蓬回的是被创斯建对象的接甘口对象,当柔然也可以是困抽象类或者疫一个具体的狂类的实例。突(5)谁来虽使用工厂方式法创建的对啄象连鸡

这里屿首先要搞明绸白一件事情帅,就是谁在季使用工厂方峰法创建的对论象?匀疾

事实伪上,在工厂毒方法模式里蛇面,应该是围Creat时or中的其渴它方法在使孤用工厂方法来创建的对象拍,虽然也可绝以把工厂方视法创建的对鹊象直接提供提给Crea士tor外部竖使用,但工树厂方法模式牵的本意,是侍由Crea露tor对象摇内部的方法获来使用工厂别方法创建的节对象,也就是是说,工厂晕方法一般不音提供给Cr该eator扇外部使用。殃炉

客户竹端应该是使巴用Crea担tor对象乓,或者是使袖用由Cre却ator创嚼建出来的对昨象。对于客中户端使用C负reato朽r对象,这圾个时候工厂凑方法创建的守对象,是C交reato窗r中的某些羡方法使用。振对于使用那姓些由Cre扁ator创斯建出来的对绩象,这个时呜候工厂方法和创建的对象喷,是构成客粪户端需要的案对象的一部野分。分别举停例来说明。冻乞①姥客户端使用罗Creat方or对象的惨情况监袭

比如紧前面的示例盐,对于“实漠现导出数据与的业务功能坚对象”的类压E吹xport劫Opera的te,它有号一个exp麻ort的方亦法,在这个拥方法里面,跌需要使用具始体的“导出均的文件对象普的接口对象查”Exp障ortFi涨leApi习,而Exp谜ortOp辰erate地是不知道具土体的Exp符ortFi舟leApi弦实现的,那旺么怎么做的信呢?就是定筒义了一个工蜻厂方法,用明来返回Ex自portF翁ileAp魔i的对象,兼然后exp侨ort方法村会使用这个祥工厂方法来嫁获取它所需服要的对象,眉然后执行功功能。硬蛇

这个型时候的客户拴端是怎么做终的呢?这个叠时候客户端榆主要就是使碗用这个Ex陷portO瞎perat概e的实例来芽完成它想要振完成的功能祝,也就是客所户端使用C显reato跑r对象的情伍况,简单描秘述这种情况魄下的代码结岁构如下:

犬/**车

*敬客户端使用咐Creat亩or对象的云情况下,C喜reato垃r的基本实仪现结构金

*/文publi翼cabs尖tract醋clas恢sCre劈ator掏{碗

/稻**斜

咐*工厂方荣法,一般不房对外性

举*@re礼turn砌创建的产品冤对象洋

科*/毒

p皮rotec骆teda世bstra笔ctPr浩oduct愁fact脆oryMe娘thod(课);舍

/朴**汪

多*提供给供外部使用的炉方法,嗽

猜*客户端密一般使用C胡reato永r提供的这疤些方法来完贩成所需要的下功能课

饶*/灿

p趣ublic商void榜some妨Opera浪tion(知){枣

//在甜这里使用工科厂方法线

Pro看duct嗽p=f首actor层yMeth海od();没

}厉}搭②锈客户端使用铸由Crea嫩tor创建失出来的对象逢绸

另外国一种是由C疗reato校r向客户端来返回由“工芹厂方法创建史的对象”来套构建的对象效,这个时候树工厂方法创服建的对象,诸是构成客户祸端需要的对浓象的一部分勺。简单描述案这种情况下各的代码结构狂如下:

瞎/**撒

*摔客户端使用叮Creat念or来创建酱客户端需要争的对象的情汁况下,Cr亦eator秋的基本实现些结构啦

*/袭publi阳cabs秃tract怖clas困sCre鞠ator佳{乐

/闭**击

非*工厂方凳法,一般不血对外,创建悄一个部件对璃象圈

挠*@re饿turn君创建的产品叠对象,一般僻是另一个产汤品对象的部蹦件华

己*/忘

p衰rotec末teda蛛bstra治ctPr滔oduct六1fac骆toryM筑ethod朽1();应

/环**赞

讨*工厂方猫法,一般不烦对外,创建杨一个部件对胖象阵

滔*@永retur窑n创建的杨产品对象,抬一般是另一菠个产品对象从的部件上

纠*/权

p成rotec贪teda芝bstra呜ctPr材oduct删2fac膀toryM右ethod兼2();顺

/导**猎

继*创建客铲户端需要的惕对象,客户功端主要使用纯产品对象来饥完成所需要勤的功能袍

面*@re首turn捞客户端需要何的对象渣

拆*/暑

p补ublic晨Prod肉uctc茶reate队Produ痰ct(){讨

//在乏这里使用工仆厂方法,得虏到客户端所绝需对象的部房件对象稳

Pro湾duct1说p1=葵fact篮oryMe套thod1佛();袄

Pro淡duct2朋p2=度fact汤oryMe固thod2培();耍

//工李厂方法创建衬的对象是创璃建客户端对贿象所需要的袜

Pro移duct液p=n推ewCo刊ncret羽eProd选uct()篮;昼

p.s蹲etPro息duct1建(p1);遵

p.s钞etPro丝duct2堆(p2);瓜

ret汗urnp艘;构

}卫}广除

小结夏一下:在工吩厂方法模式俭里面,客户捷端要么使用肌Creat豆or恭对象,要么家使用Cre朱ator创梯建的对象,窜一般客户端括不直接使用崇工厂方法。倒当然也可以要直接把工厂摄方法暴露给啄客户端操作命,但是一般甩不这么做。扯(6)工厂萄方法模式的速调用顺序示横意图破寺

由于盛客户端使用舞Creat叨or对象有剃两种典型的时情况,因此吗调用的顺序鼻示意图也分窗做两种情况魄,先看看客税户端使用由仓Creat乔or创建出蔽来的对象情塑况的调用顺钓序示意图,鸦如图5所示鸭:备贴凳

图5辞

客户端历使用由Cr统eator阁创建出来的瑞对象的调用沃顺序示意图拍接下来看看捷客户端使用证Creat培or对象时句候的调用顺某序示意图,踪如图6所示趋:康细沈

图并6

客户剃端使用Cr锋eator窑对象的调用乱顺序示意图顶研磨设计模探式之工厂恋方法模式-己4介3.2

榆工厂方法模徐式与IoC惜/DI舱

IoC—讨—Inve劣rsion民ofC财ontro叠l

控制赔反转济

DI——虎Depen绸dency择Inje病ction玻

依赖拖注入脑1:如何理闸解IoC/驼DI赏许

要想件理解上面两让个概念,就便必须搞清楚阀如下的问题楼:跑参与者都有飞谁?季依赖:谁依滔赖于谁?为表什么需要依换赖?

绸注入:谁注愈入于谁?到脑底注入什么面?肃控制反转:宗谁控制谁?薯控制什么?汁为何叫反转涛(有反转就淡应该有正转运了)?闯依赖注入和织控制反转是兴同一概念吗羞?见舅

下面吧就来简要的屑回答一下上砍述问题,把剖这些问题搞猴明白了,I自oC/DI喜也就明白了鱼。走(1)参与恰者都有谁:涛兽

一般羽有三方参与离者,一个是巾某个对象;赏一个是Io旁C/DI的患容器;另一拥个是某个对狱象的外部资抓源。全释

又要语名词解释一章下,某个对神象指的就是州任意的、普桥通的Jav蚁a对象;挥IoC/D糊I的容器简旷单点说就是吸指用来实现揭IoC/D渠I功能的一夸个框架程序饰;对象的外睬部资源指的纠就是对象需宝要的,但是矿是从对象外财部获取的,蚂都统称资源确,比如:对津象需要的其滩它对象、或均者是对象需欺要的文件资僻源等等。驳(2)谁依巾赖于谁:逃终

当然宏是某个对象消依赖于Io器C/DI的睛容器弟(3)为什常么需要依赖旅:辱彼

对象道需要IoC绑/DI的容世器来提供对凉象需要的外半部资源滨(4)谁注偷入于谁:他道

很明内显是IoC驴/DI的容熟器注入镰某个对象行(5)到底陵注入什么:河匪

就是头注入某个对朴象所需要的晒外部资源严(6)谁控泪制谁:挑酱

当然抚是IoC/铲DI的容器设来控制对象渐了拘(7)控制轿什么:掩泡

主要青是控制对象挖实例的创建现(8)为何辽叫反转:屑凳

反转旺是相对于正拳向而言的,歉那么什么算尊是正向的呢气?考虑一下为常规情况下皇的应用程序脊,如果要在早A里面使用塔C,你会怎沸么做呢?当录然是直接去售创建C的对感象,也就是递说,是在A锡类中主动去偏获取所需要葱的外部资源彼C,这种情被况被称为正症向的。那么筛什么是反向渔呢?就是A分类不再主动梳去获取C,林而是被动等笑待,等待I欣oC/DI湿的容器获取幻一个C的实围例,然后反锦向的注入到什A类中。听鱼

用图绢例来说明一悟下,先看没捡有IoC/炼DI的时候欠,常规的A爱类使用C类箱的示意图,兄如图7所示资:肚意桨铜糖道漆况

图7斧

常规A兼使用C示意拨图太当有了Io惹C/DI的塌容器后,A惭类不再主动谊去创建C了稻,如图8所势示:初给路孙遭思尝倾

图8

炸A类不再美主动创建C伐而是被动等篮待,等待I怀oC/DI贪的容器获取觉一个C的实纽例,然后反盟向的注入到龄A类中,如联图9所示:唱粘日铲恩丧压乌颤械

图9

栏有IoC鸟/DI容器尼后程序结构酬示意图照(9)依赖躺注入和控制迅反转是同一赛概念吗?应脏

根据咽上面的讲述樱,应该能看像出来,依赖小注入和控制冰反转是对同板一件事情的锯不同描述,爪从某个方面铃讲,就是它梢们描述的角缠度不同。依雁赖注入是从矩应用程序的武角度在描述各,可以把依饺赖注入描述值完整点:应倒用程序依赖膛容器创建并胳注入它所需剩要的外部资喷源;而控制差反转是从容隔器的角度在教描述,描述肝完整点:容以器控制应用叮程序,由容砌器反向的向合应用程序注塘入应用程序火所需要的外怪部资源。羡(10)小倒结一下:沸续

其实妇IoC/D辩I对编程带测来的最大改挡变不是从代凶码上,而是痒从思想上,领发生了“主窄从换位”的消变化。应用疼程序原本是海老大,要获屈取什么资源扎都是主动出叔击,但是在衣IoC/D青I思想中,捉应用程序就嘱变成被动的验了,被动的瓜等待IoC斜/DI容器阶来创建并注询入它所需要绕的资源了。份吐

这么般小小的一个枕改变其实是陈编程思想的鞠一个大进步砖,这样就有屑效的分离了堪对象和它所逝需要的外部堆资源,使得刊它们松散耦灭合,有利于岗功能复用,楚更重要的是忆使得程序的琴整个体系结涉构变得非常音灵活。宏2:工厂方冰法模式和I熟oC/DI陕有什么关系茅呢?羊吩

从某兔个角度讲,芳它们的思想梳很类似。躲成

上面钱讲了,有了洞IoC/D厕I过后,应捷用程序就不箭再主动了,籍而是被动等项待由容器来不注入资源,偿那么在编写处代码的时候腾,一旦要用积到外部资源站,就会开一范个窗口,让腊容器能注入刃进来,也就枣是提供给容昼器使用的注范入的途径,矮当然这不是颈我们的重点理,就不去细慎细讲了,用的sette恳r注入来示貌例一下,看抵看使用Io药C/DI的炕代码是什么瓦样子,示例喷代码如下:涂寒publi列ccla贯ssA鼠{慢

/睡**怀

露*等待被嫌注入进来煮

欧*/帝

p烛rivat燕eCc交=nu扁ll;琴

/匆**颤

汇*注入资寇源C的方法役

筑*@pa居ramc钢被注入的棋资源原

槽*/猜

p态ublic己void启setC妖(Cc)么{获

thi岛s.c=就c;惊

}裁

p变ublic费void去t1()斗{付

//这拴里需要使用单C,可是又确不让主动去队创建C了,笨怎么办?撑

//反夫正就要求从李外部注入,初这样更省心光,螺

//自辫己不用管怎贿么获取C,厅直接使用就梨好了奸

乌c.tc(避);巷

}光}忆接口C的示痒例代码如下其:

亡publi将cint翻erfac凭eC{笨

p股ublic拾void贝tc()副;距}占洪

从上辣面的示例代扶码可以看出恩,现在在A醒里面写代码鲜的时候,凡区是碰到了需积要外部资源惨,那么就提臣供注入的途卖径,要求从针外部注入,踢自己只管使瞎用这些对象洽。怠缝

再来才看看工厂方效法模式,如超何实现上面槽同样的功能者,为了区分席,分别取名颤为A1和C健1。这个时右候在A1里委面要使用C切1对象,也赢不是由A1熟主动去获取拉C1对象,己而是创建一依个工厂方法玩,就类似于救一个注入的绳途径;然后验由子类,假洽设叫A2吧皱,由A2来哨获取C1对现象,在调用世的时候,替坛换掉A1的碗相应方法,句相当于反向搁注入回到A绵1里面,示尖例代码如下畅:

攻publi振cabs吸tract诵clas贵sA1窑{偷

/岂**姥

筛*工厂方坡法,创建C得1,类似于啄从子类注入辽进来的途径泳

绞*@re窑turn打C1的对象早实例墨

停*/监

p臣rotec捆teda革bstra甘ctC1何crea杰teC1(蓄);口

p杜ublic敏void挨t1()阴{滔

衫//这里需后要使用C1城类,可是不权知道究竟是删用哪一个公

//也添就不主动去生创建C1了内,怎么办?攀

//反锡正会在子类弃里面实现,狼这里不用管雷怎么获取C稼1,直接使齐用就好了目

cre轨ateC1酱().tc情();动

}部}大子类的示例会代码如下:愚甩publi丈ccla权ssA2摘exte托ndsA丰1{吐

p索rotec舱tedC弓1cre序ateC1锈(){顿

//真蜡正的选择具御体实现,并部创建对象佣

ret肠urnn井ewC2慌();熟

}榴}是新

C盟1接口和前暂面C接口是虚一样的,C棉2这个实现习类也是空的鸟,只是演示挎一下,因此大就不去展示依它们的代码址了。迅弱

仔细老体会上面的易示例,对比兽它们的实现芹,尤其是从寺思想层面上拿,会发现工胳厂方法模式篇和IoC/诱DI的思想幼是相似的,微都是“杠主动变被动立”,进行了岂“黄主从换位援”,从而获抱得了更灵活打的程序结构趁。抚研磨设计模适式之工厂至方法模式-魔5半3.3

役平行的类层闯次结构呜(1)什么绿是平行的类刮层次结构呢赚?燕

简单娘点说,假如瑞有两个类层腥次结构,其幅中一个类层哥次中的每个守类在另一个篮类层次中都当有一个对应竹的类的结构亏,就被称为颤平行的类层梢次结构。仍举个例逮子来说,硬眨盘对象有很阁多种,如分锣成台式机硬虎盘和笔记本社硬盘,在台细式机硬盘的马具体实现上白面,又有希绑捷、西数等子不同品牌的翁实现,同样贴在笔记本硬狸盘上,也有矩希捷、日立消、IBM等里不同品牌的处实现;硬盘炮对象具有自抹己的行为,压如硬盘能存夏储数据,也苗能从硬盘上抽获取数据,著不同的硬盘险对象对应的毯行为对象是复不一样的,惕因为不同的偿硬盘对象,雁它的行为的啄实现方式是仗不一样的。镜如果把硬盘矿对象和硬盘糊对象的行为咽分开描述,重那么就构成楚了如图10漠所示的结构旱:看图10

崇平行的类层胃次结构示意痛图庄硬盘对租象是一个类根层次,硬盘怒的行为这边排也是一个类坛层次,而且帝两个类层次艳中的类是对衰应的。台式原机西捷硬盘邻对象就对应僵着硬盘行为担里面的台式华机西捷硬盘被的行为;笔渴记本IBM张硬盘就对应锤着笔记本I富BM硬盘的覆行为,这就令是一种典型颤的平行的类胀层次结构。通这种平聚行的类层次治结构用来干首什么呢?主煮要用来把一陈个类层次中李的某些行为除分离出来,爪让类层次中爆的类把原本检属于自己的脏职责,委托逗给分离出来箩的类去实现胆,从而使得月类层次本身宜变得更简单跃,更容易扩场展和复用。然一般来煌讲,分离出赵去的这些类急的行为,会胖对应着类层丘次结构来组匆织,从而形洽成一个新的健类层次结构付,相当于原滑来对象的行墓为的这么一晶个类层次结锋构,而这个她层次结构和饶原来的类层玉次结构是存馅在对应关系爱的,因此被劳称为平行的萌类层次结构咸。刺(2)工厂唤方法模式跟蔽平行的类层奋次结构有何欠关系呢?机可以使攀用工厂方法集模式来连接握平行的类层丘次。昂看上面猫的示例图1表0,在每个听硬盘对象里盖面,都有一党个工厂方法稻creat斯eHDOp互erate的,通过这个背工厂方法,颗客户端就可他以获取一个纪跟硬盘对象舟相对应的行换为对象。在笼硬盘对象的牙子类里面,尊会覆盖父类狡的工厂方法越creat眠eHDOp乐erate给,以提供跟拉自身相对应苏的行为对象股,从而自然洲的把两个平暂行的类层次槐连接起来使包用。帜3.4

壳参数化工厂晃方法狼所谓参判数化工厂方瓣法指的就是梳:添通过给工厂份方法传递参振数,让工厂窝方法根据参尼数的不同来万创建不同的孔产品对象,梦这种情况就议被称为参数抛化工厂方法便。当然工厂辈方法创建的厕不同的产品脾必须是同一托个Prod摊uct类型国的。役来改造奴前面的示例地,现在有一堤个工厂方法日来创建Ex译portF肠ileAp议i这个产品史的对象,但顾是Expo千rtFil址eApi接掩口的具体实括现很多,为寿了方便创建晴的选择,直罪接从客户端犹传入一个参调数,这样在丢需要创建E碰xport莫FileA钩pi对象的宋时候,就把艇这个参数传送递给工厂方根法,让工厂午方法来实例亡化具体的E竟xport验FileA盯pi实现对图象。园还是看轧看代码示例矩会比较清楚殖。挽(1)先来己看Prod尊uct的接船口,就是E蛇xport萝FileA科pi接口,叔跟前面的示将例没有任何浆变化,为了锁方便大家查测看,这里重铸复一下,示甲例代码如下侵:

桶/**兵

*导出辰的文件对象着的接口彼

*/聚publi罪cint扩erfac灵eExp叨ortFi刚leApi燥{秩

/各**侍

飘*导出内宜容成为文件枝

盗*@pa械ramd巾ata示搏意:需要保描存的数据茧

窃*@re寺turn猴是否导出成负功缎

巴*/既

p勤ublic近bool织eane耀xport伟(Stri婚ngda比ta);溜}勾(2)同样选提供保存成沉文本文件和搭保存成数据塞库备份文件浩的实现,跟只前面的示例极没有任何变刚化,示例代统码如下:

甘publi建ccla燃ssEx党portT川xtFil寨eimp疮lemen粥tsEx皇portF哑ileAp扎i{示

p炉ublic黎bool护eane嘱xport油(Stri疑ngda源ta){犬

//简挖单示意一下何,这里需要织操作文件葱

Sys令tem.刚out充.prin庄tln("蛋导出数据"吉+data他+"到文本革文件");愈

ret测urnt善rue;筝

}极}握publi阳ccla齿ssEx主portD蕉Bimp糟lemen车tsEx络portF音ileAp傅i{哄

p握ublic壶bool剖eane纠xport掌(Stri蓄ngda尝ta){蛛

//简呜单示意一下奥,这里需要限操作数据库府和文件笑

Sys栗tem.术out尤.prin孤tln("耽导出数据"刚+data业+"到数据蹄库备份文件肝");毛

ret筹urnt族rue;俗

}翼}济(3)接下某来该看看E祝xport诊Opera狡te类了,玩这个类的变佩化大致如下后:夺Expor辆tOper希ate类中融的创建产品栗的工厂方法增,通常需要疫提供默认的捉实现,不抽块象了,也就患是变成正常土方法鼠Expor萌tOper粘ate类也像不再定义成悬抽象类了,辉因为有了默饿认的实现,阔客户端可能过需要直接使厉用这个对象宏胸设置一个导酱出类型的参剖数,通过e借xport疑方法从客户猎端传入笔看看代狂码吧,示例取代码如下:喇揭/**完

*实现患导出数据的炒业务功能对绘象尾

*/种publi偷ccla隐ssEx吧portO死perat睁e{怕

/胁**骑

包*导出文班件搜

援*@pa蕉ramt睡ype用弓户选择的导绩出类型塞

泉*@pa躺ramd免ata需闸要保存的数混据奏

煎*@re贯turn宁是否成功导菊出文件黄

欠*/壶

p纱ublic被bool披eane义xport例(int陷type,磨Strin仙gdat刃a){风

//使如用工厂方法纳

Exp殖ortFi嚼leApi化api颂=fac无toryM缠ethod巩(type脊);灿

ret绑urna杏pi.ex欢port(松data)习;柴

}岭

/霉**侮

事*工厂方葵法,创建导展出的文件对叮象的接口对跨象左

释*@pa春ramt汉ype用挑户选择的导旗出类型泼

孙*@re捕turn余导出的文件茧对象的接口误对象饲

妥*/云

p广rotec堤tedE辜xport爷FileA松pifa稻ctory辜Metho鸣d(int滔type勾){亚

Expo架rtFil名eApi文api=围null糖;骨

教//根据类险型来选择究它竟要创建哪朴一种导出文捷件对象

if(裂type=趟=1){售

纸api骄=new择Expo鄙rtTxt查File(糟);竹

}el下seif循(type腰==2){状

装api窗=new泼Expo白rtDB(能);母

}泛

ret猎urna甘pi;俭

}贡}复(4)此时灶的客户端,脑非常简单,燥直接使用E泊xport损Opera镰te类,示任例代码如下启:

衫publi误ccla门ssCl证ient轨{湾

p奸ublic粒stat掏icvo涉idma刚in(St娇ring[敬]arg答s){路

//遗创建需要使绣用的Cre妨ator对绘象兴

Exp服ortOp睡erate我oper冒ate=初new扛Expor阅tOper鹅ate()逐;撇

锈//调用输柴出数据的功恶能方法,传隐入选择到处税类型的参数角

宿

ope宅rate.伯expor洲t(1,"煎测试数据"或);旧

}照}榴测试看胡看,然后修究改一下客户源端的参数,扒体会一下通欢过参数来选留择具体的导衰出实现的过聋程。这是一待种很常见的济参数化工厂芦方法的实现窑方式,但是日也还是有把发参数化工厂殊方法实现成跟为抽象的,青这点要注意校,并不是说踪参数化工厂描方法就不能造实现成为抽台象类了。只号是一般情况摊下,参数化宰工厂方法,宜在父类都会葬提供默认的扇实现。吩(5)扩展久新的实现园啊使用参数化平工厂方法,喉扩展起来会却非常容易告,已有的代列码都不会改截变,只要新嚼加入一个子疤类来提供新驾的工厂方法漆实现,然后壮在客户端使墨用这个新的订子类即可。跟这种实影现方式还有良一个有意思辩的功能,就圣是子类可以屡选择性覆盖略,不想覆盖悟的功能还可础以返回去让偿父类来实现捧,很有意思误。水先扩展凝一个导出成妇xml文件年的实现,试末试看,示例座代码如下:堵贺/**卧

*导出凤成xml文绵件的对象析

*/行publi嫌ccla结ssEx凳portX吼mlim酱pleme烧ntsE抬xport射FileA臭pi{促

p德ublic针bool挎eane貌xport泽(Stri砍ngda千ta){乘

//简坊单示意一下仪

Sys责tem.彼out底.prin宪tln("雕导出数据"药+data既+"到XM认L文件")糖;灰

re歉turn絮true;帐

}播}将然后扩展E武xport酬Opera湾te类,来厚加入新的实为现,示例代亭码如下:

聚/**悉

*扩展岗Expor和tOper赢ate对象朝,加入可以颜导出XML约文件猜

*/素publi凉ccla悉ssEx茶portO粪perat皂e2ex破tends健Expo脊rtOpe鲁rate{寻

/葱**榴

觉*覆盖父破类的工厂方衣法,创建导误出的文件对唱象的接口对慕象也

于*@pa陈ramt率ype用昨户选择的导笋出类型控

翼*@re尊turn裳导出的文件子对象的接口桥对象猎

诉*/赶

p诵rotec技tedE夜xport伶FileA岸pifa船ctory随Metho婚d(int做type听){郊

Exp询ortFi竿leApi霸api窑=nul显l;倍

另//可以全财部覆盖,也讯可以选择自柜己感兴趣的善覆盖,

//这洁里只想添加策自己新的实理现,其它的哲不管

if(响type=嗓=3){坟

齐api碌=new隶Expo硬rtXml鞭();痕

}el皂se{泉

格//其它身的还是让父前类来实现

狼api耀=sup倍er.fa黎ctory蒜Metho殊d(typ苏e);捷

}煌

ret赖urna挖pi;萝

}臂}情看看此时的幸客户端,也队非常简单,跪只是在变换阴传入的参数走,示例代码恼如下:

亦publi狸ccla盾ssCl茅ient怀{纵

p乎ublic眠stat意icvo辫idma像in(St堵ring[递]arg炸s){户

//创尤建需要使用穷的Crea令tor对象昆

Exp俩ortOp偶erate弟oper岩ate=咐new调Expor裕tOper音ate2(开);呜

//下洲面变换传入仍的参数来测牢试参数化工撑厂方法毫

ope弄rate.末expor文t(1,"雹Test1女");舌

ope惰rate.仍expor馋t(2,"章Test2山");袜

ope点rate.谅expor遍t(3,"海Test3渡");光

}岔}桌对应的测试波结果如下:绞先导出数据T鹅est1到触文本文件唤导出数据T化est2到浊数据库备份是文件板导出数据T勇est3到贺XML文件累通过上面的侧示例,好好拖体会一下参趋数化工厂方尼法的实现和宵带来的好处伸。吐3.5

车工厂方法模昼式

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论