Java设计模式之工厂模式(Factory)

Java设计模式之工厂模式(Factory) 时间:2009-08-04 17:23 来源:未知 作者:和水柔石 CSDN IE QQ 百度 我挖 Google POCO Yahoo 新浪 365Key 天极 和讯 博拉 Live 奇客 鲜果 收客 饭否 叽歪 挖客 核心提示::作者::和水柔柔石 一一、引子子 话说说十年前前,有一一个爆发发户,他他家有三三辆汽车车(Beenz (奔驰驰)、BBmw (宝马马)、AAudii (奥奥迪)看看来这人人比较爱爱国,没没有日本本车),还还雇了司司机为他他开车不不过,爆爆发户坐坐车时总总是这样样:上BBenzz 车后后跟司机机说 开开奔驰车车! ,坐坐上Bmmw 后后他说 开 作者:和水水柔石 一、引子话话说十年年前,有有一个爆爆发户,他他家有三三辆汽车车(Beenz (奔驰驰)、BBmw (宝马马)、AAudii (奥奥迪)看看来这人人比较爱爱国,没没有日本本车),还还雇了司司机为他他开车不不过,爆爆发户坐坐车时总总是这样样:上BBenzz 车后后跟司机机说" 开奔驰驰车!"" ,坐坐上Bmmw 后后他说"" 开宝宝马车!!" ,坐坐上Auudi 后他说说" 开开奥迪车车!" 。
你你一定说说:这人人有病!!直接说说开车不不就行了了?! 而当把把这个爆爆发户的的行为放放到我们们程序语语言中来来,我们们发现CC 语言言一直是是通过这这种方式式来坐车车的! 幸运的的是,这这种有病病的现象象在OOO 语言言中可以以避免了了下面面以Jaava 语言为为基础来来引入我我们本文文的主题题:工厂厂模式!!! 二、简介工工厂模式式主要是是为创建建对象提提供了接接口工工厂模式式按照《JJavaa 与模模式》中中的提法法分为三三类:11. 简简单工厂厂模式((Simmplee Faactoory)) 2.. 工厂厂方法模模式(FFacttoryy Meethood) 3. 抽象工工厂模式式(Abbstrractt Faactoory)) 这三三种模式式从上到到下逐步步抽象,并并且更具具一般性性还有有一种分分类法,就就是将简简单工厂厂模式看看为工厂厂方法模模式的一一种特例例,两个个归为一一类下下面是使使用工厂厂模式的的两种情情况:11. 在在编码时时不能预预见需要要创建哪哪种类的的实例2. 系统不应依赖于产品类实例如何被创建、组合和表达的细节 三、简单工工厂模式式顾名思思义,这这个模式式本身很很简单,而而且使用用在业务务较简单单的情况况下。
它它由三种种角色组组成(关关系见下下面的类类图)::1、工工厂类角角色:这这是本模模式的核核心,含含有一定定的商业业逻辑和和判断逻逻辑在在javva 中中它往往往由一个个具体类类实现 2、抽抽象产品品角色::它一般般是具体体产品继继承的父父类或者者实现的的接口在在javva 中中由接口口或者抽抽象类来来实现 3、具具体产品品角色::工厂类类所创建建的对象象就是此此角色的的实例在在javva 中中由一个个具体类类实现 那么简简单工厂厂模式怎怎么用呢呢?我来来举个例例子吧,我我想这个个比讲一一大段理理论上的的文字描描述要容容易理解解的多!!下面就就来给那那个暴发发户治病病: PP 在使使用了简简单工厂厂模式后后,现在在暴发户户只需要要坐在车车里对司司机说句句:" 开车"" 就可可以了来来看看怎怎么实现现的:1. // 抽象象产品角角色 2. publiic intterffacee Caar{ 3. publiic voiid ddrivve()); 4. } 5. // 具体体产品角角色 6. publiic claass Bennz iimpllemeentss Caar{ 7. publiic voiid ddrivve()) { 8. Systeem.oout..priintlln(""Driivinng BBenzz ")); 9. } 10. } 11. 12. publiic claass Bmww immpleemennts Carr{ 13. publiic voiid ddrivve()) { 14. Systeem.oout..priintlln(""Driivinng BBmw ");; 15. } 16. } 。
奥奥迪我就就不写了了:P ) 1. // 工厂厂类角色色 2. publiic claass Driiverr{ 3. 4. // 工厂厂方法 5. // 注意意 返回回类型为为抽象产产品角色色 6. publiic staaticc Caar ddrivverCCar((Strringg s))thrrowss Exxcepptioon {{ 7. 8. // 判断断逻辑,返返回具体体的产品品角色给给Cliientt 9. if(s..equualssIgnnoreeCasse(""Bennz"))) rretuurn neww Beenz((); 10. else if(ss.eqquallsIggnorreCaase(("Bmmw"))) 11. returrn neww Bmmw()); 12. 13. ....... 14. else thrrow neww Exxcepptioon()); 15. 16. 17. // 欢迎迎暴发户户出场........ 18. publiic claass Maggnatte{ 19. publiic staaticc voiid mmainn(Sttrinng[]] arrgs)){ 20. try{ 21. // 告诉诉司机我我今天坐坐奔驰 22. Car ccar = DDrivver..driiverrCarr("bbenzz");; 23. // 下命命令:开开车 24. car.ddrivve()); 25. 。
如果将所有有的类放放在一个个文件中中,请不不要忘记记只能有有一个类类被声明明为puubliic 程序中中类之间间的关系系如下:: 这便是简单单工厂模模式了下下面是其其好处:: 首先先,使用用了简单单工厂模模式后,我我们的程程序不在在" 有有病" ,更加加符合现现实中的的情况;;而且客客户端免免除了直直接创建建产品对对象的责责任,而而仅仅负负责" 消费"" 产品品(正如如暴发户户所为)下面我们从开闭原则上来分析下简单工厂模式当暴发户增加了一辆车的时候,只要符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了那么对于产品部分来说,它是符合开闭原则的-- 对扩展开放、对修改关闭;但是工厂部分好像不太理想,因为每增加一辆车,都要在工厂类中增加相应的商业逻辑和判断逻辑,这显自然是违背开闭原则的对于这样的工厂类(在我们的例子中是为司机师傅),我们称它为全能类或者上帝类我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝类坏了,进而累坏了我们可爱的程序员:( 正如我前面提到的简单工厂模式适用于业务将简单的情况下。
而对于复杂的业务环境可能不太适应阿这就应该由工厂方法模式来出场了!! 四、工厂方方法模式式先来看看下它的的组成吧吧:1、抽抽象工厂厂角色::这是工工厂方法法模式的的核心,它它与应用用程序无无关是是具体工工厂角色色必须实实现的接接口或者者必须继继承的父父类在在javva 中中它由抽抽象类或或者接口口来实现现2、具具体工厂厂角色::它含有有和具体体业务逻逻辑有关关的代码码由应应用程序序调用以以创建对对应的具具体产品品的对象象在jjavaa 中它它由具体体的类来来实现3、抽象产品角色:它是具体产品继承的父类或者是实现的接口在java 中一般有抽象类或者接口来实现4、具体产品角色:具体工厂角色所创建的对象就是此角色的实例在java 中由具体的类来实现来用类图来清晰的表示下的它们之间的关系: 我们还是老老规矩使使用一个个完整的的例子来来看看工工厂模式式各个角角色之间间是如何何来协调调的话话说暴发发户生意意越做越越大,自自己的爱爱车也越越来越多多这可可苦了那那位司机机师傅了了,什么么车它都都要记得得,维护护,都要要经过他他来使用用!于是是暴发户户同情他他说:看看你跟我我这么多多年的份份上,以以后你不不用这么么辛苦了了,我给给你分配配几个人人手,你你只管管管好他们们就行了了!于是是,工厂厂方法模模式的管管理出现现了。
代代码如下下:1. // 抽象象产品角角色,具具体产品品角色与与简单工工厂模式式类似,只只是变得得复杂了了些,这这里略 2. // 抽象象工厂角角色 3. publiic intterffacee Drriveer{ 4. publiic CCar driiverrCarr();; 5. } 6. publiic claass BennzDrriveer iimpllemeentss Drriveer{ 7. publiic CCar driiverrCarr(){{ 8. returrn neww Beenz((); 9. } 10. } 11. publiic claass BmwwDriiverr immpleemennts Driiverr{ 12. publiic CCar driiverrCarr() { 13. returrn neww Bmmw()); 14. } 15. } 16. ......./// 应该该和具体体产品形形成对应应关系,这这里略.... 17. // 有请请暴发户户先生 18. publiic claass Maggnatte 19. { 20. publiic staaticc voiid mmainn(Sttrinng[]] arrgs)) 21. { 22. try{ 23. Driveer ddrivver = nnew BennzDrriveer()); 24. 25. Car ccar = ddrivver..driiverrCarr();; 26. car.ddrivve()); 27. }catcch(EExceeptiion e) 28. { } 29. } 30. } 工厂方法使使用一个个抽象工工厂角色色作为核核心来代代替在简简单工厂厂模式中中使用具具体类作作为核心心。
让我我们来看看看工厂厂方法模模式给我我们带来来了什么么?使用用开闭原原则来分分析下工工厂方法法模式当当有新的的产品(即即暴发户户的汽车车)产生生时,只只要按照照抽象产产品角色色、抽象象工厂角角色提供供的合同同来生成成,那么么就可以以被客户户使用,而而不必去去修改任任何已有有的代码码看来来,工厂厂方法模模式是完完全符合合开闭原原则的!!使用工工厂方法法模式足足以应付付我们可可能遇到到的大部部分业务务需求但但是当产产品种类类非常多多时,就就会出现现大量的的与之对对应的工工厂类,这这不应该该是我们们所希望望的所所以我建建议在这这种情况况下使用用简单工工厂模式式与工厂厂方法模模式相结结合的方方式来减减少工厂厂类:即即对于产产品树上上类似的的种类(一一般是树树的叶子子中互为为兄弟的的)使用用简单工工厂模式式来实现现当然然特殊的的情况,就就要特殊殊对待了了:对于于系统中中存在不不同的产产品树,而而且产品品树上存存在产品品族,那那么这种种情况下下就可能能可以使使用抽象象工厂模模式了 五、小结让让我们来来看看简简单工厂厂模式、工工厂方法法模式给给我们的的启迪::如果不不使用工工厂模式式来实现现我们的的例子,也也许代码码会减少少很多--- 只只需要实实现已有有的车,不不使用多多态。
但但是在可可维护性性上,可可扩展性性上是非非常差的的(你可可以想象象一下,添添加一辆辆车后要要牵动的的类)因因此为了了提高扩扩展性和和维护性性,多写写些代码码是值得得的 六、抽象工工厂模式式先来认认识下什什么是产产品族::位于不不同产品品等级结结构中,功功能相关关联的产产品组成成的家族族如果果光看这这句话就就能清楚楚的理解解这个概概念,我我不得不不佩服你你啊还还是让我我们用一一个例子子来形象象地说明明一下吧吧 图中的BmmwCaar 和和BennzCaar 就就是两个个产品树树(产品品层次结结构);;而如图图所示的的BennzSpporttsCaar 和和BmwwSpoortssCarr 就是是一个产产品族他他们都可可以放到到跑车家家族中,因因此功能能有所关关联同同理BmmwBuussiinesssCaar 和和BennzSpporttsCaar 也也是一个个产品族族回到到抽象产产品模式式的话题题上,可可以这么么说,它它和工厂厂方法模模式的区区别就在在于需要要创建对对象的复复杂程度度上而而且抽象象工厂模模式是三三个里面面最为抽抽象、最最具一般般性的抽抽象工厂厂模式的的用意为为:给客客户端提提供一个个接口,可可以创建建多个产产品族中中的产品品对象。
而而且使用用抽象工工厂模式式还要满满足一下下条件::1. 系统中中有多个个产品族族,而系系统一次次只可能能消费其其中一族族产品22. 同同属于同同一个产产品族的的产品以以其使用用来看看看抽象象工厂模模式的各各个角色色(和工工厂方法法的如出出一辙)::抽象工工厂角色色:这是是工厂方方法模式式的核心心,它与与应用程程序无关关是具具体工厂厂角色必必须实现现的接口口或者必必须继承承的父类类在jjavaa 中它它由抽象象类或者者接口来来实现具体工厂角色:它含有和具体业务逻辑有关的代码由应用程序调用以创建对应的具体产品的对象在java 中它由具体的类来实现抽象产品角色:它是具体产品继承的父类或者是实现的接口在java 中一般有抽象类或者接口来实现具体产品角色:具体工厂角色所创建的对象就是此角色的实例在java 中由具体的类来实现 看过了前两两个模式式,对这这个模式式各个角角色之间间的协调调情况应应该心里里有个数数了,我我就不举举具体的的例子了了只是是一定要要注意满满足使用用抽象工工厂模式式的条件件哦,不不然即使使存在了了多个产产品树,也也存在产产品族,但但是不能能使用的的 附带一个例例子:hhttpp:///wwww.bllogjjavaa.neet/fflusstarr/arrchiive//20007/111/229/ffacttoryyMetthodd.httml 1. Factoory Metthodd模式 2. publiic abbstrractt claass Baall { 3. pprottectted absstraact voiid plaay()); 4. } 5. 6. publiic cllasss BBaskketbballl eexteendss BBalll { 7. 8. pprottectted vvoidd pplayy() { 9. Sysstemm.ouut.pprinntlnn("pplayy thhe bbaskketbballl" )); 10. }} 11. } 12. 13. publiic cllasss FFoottballl exttendds Balll {{ 14. 15. pprottectted vvoidd pplayy() { 16. Sysstemm.ouut.pprinntlnn("pplayy thhe ffoottballl" ); 17. }} 18. } 19. 20. publiic abbstrractt claass BaallFFacttoryy { 21. pprottectted absstraact Baall makkeBaall((); 22. } 23. 24. publiic cllasss BBaskketbballlFacct exttendds BalllFaactoory { 25. 26. pprottectted Baall makkeBaall(() {{ 27. retturnn neww BBaskketbballl();; 28. }} 29. } 30. 31. publiic cllasss FFoottballlFaact exxtennds BaallFFacttoryy { 32. 33. pprottectted Baall makkeBaall(() {{ 34. retturnn neww FFoottballl()); 35. }} 36. } 37. 38. publiic cllasss CClieent { 39. 40. ppubllic sstattic vvoidd mmainn(Sttrinng[]] arrgs)) { 41. 42. BalllFaactoory balllFaactoory = nnew BaaskeetbaallFFactt();; 43. Balll bbaskketbballl = balllFaactoory..makkeBaall((); 44. basskettballl.pplayy();; 45. 46. balllFaactoory = nnew FoootbballlFacct()); 47. Balll ffoottballl == baallFFacttoryy.maakeBBalll();; 48. foootbaall..plaay()); 49. }} 50. } 。